import { component$ } from '@qwik.dev/core';
import { routeAction$, routeLoader$, validator$, z, zod$ } from '@qwik.dev/router';
import type {
  ActionOptions,
  JSONObject,
  RequestEventAction,
  ValidatorErrorType,
} from 'packages/qwik-router/src/runtime/src/types';

type TypedDataValidatorError = ValidatorErrorType<{
  category: 'bird' | 'dog' | 'rat';
}>;

const typedDataValidator = zod$({
  category: z.enum(['bird', 'dog', 'rat']),
});

interface DataValidatorError {
  message: string;
}

const dataValidator = validator$((ev) => {
  if (ev.query.get('secret') === '123') {
    return {
      success: true,
    };
  }
  return {
    success: false,
    error: {
      message: 'Secret not found',
    } as DataValidatorError,
  };
});

interface ActionSuccessObject {
  actionSuccess: string;
}

interface ActionFailedObject {
  actionFail: string;
}

const actionQrl = (data: JSONObject, { fail }: RequestEventAction) => {
  if (Math.random() > 0.5) {
    return fail(500, {
      actionFail: 'secret',
    } as ActionFailedObject);
  }

  return {
    actionSuccess: 'シマエナガ',
  } as ActionSuccessObject;
};

export const useLoader = routeLoader$(() => {
  return {
    stuff: 'hello',
  };
}, dataValidator);

export const useAction1 = routeAction$(actionQrl, {
  validation: [typedDataValidator, dataValidator],
} as ActionOptions);
export const useAction2 = routeAction$(actionQrl, {
  validation: [typedDataValidator],
} as ActionOptions);
export const useAction3 = routeAction$(actionQrl, {
  validation: [dataValidator],
} as ActionOptions);
export const useAction4 = routeAction$(actionQrl, typedDataValidator, dataValidator);
export const useAction5 = routeAction$(actionQrl, typedDataValidator);
export const useAction6 = routeAction$(actionQrl, dataValidator);
export const useAction7 = routeAction$(actionQrl);
export const useAction8 = routeAction$(actionQrl, { id: 'id-action-8' });

export default component$(() => {
  const loader = useLoader();

  // Use options object, use typed data validator, use data validator
  const action1 = useAction1();
  if (action1.value) {
    if (action1.value.failed) {
      action1.value satisfies { failed: true } & (
        | TypedDataValidatorError
        | DataValidatorError
        | ActionFailedObject
      );
    } else {
      action1.value satisfies ActionSuccessObject;
    }
  }

  // Use options object, use typed data validator
  const action2 = useAction2();
  if (action2.value) {
    if (action2.value.failed) {
      action2.value satisfies { failed: true } & (TypedDataValidatorError | ActionFailedObject);
    } else {
      action2.value satisfies ActionSuccessObject;
    }
  }

  // Use options object, use data validator
  const action3 = useAction3();
  if (action3.value) {
    if (action3.value.failed) {
      action3.value satisfies { failed: true } & (DataValidatorError | ActionFailedObject);
    } else {
      action3.value satisfies ActionSuccessObject;
    }
  }

  // Use typed data validator, use data validator
  const action4 = useAction4();
  if (action4.value) {
    if (action4.value.failed) {
      action4.value satisfies { failed: true } & (
        | TypedDataValidatorError
        | DataValidatorError
        | ActionFailedObject
      );
    } else {
      action4.value satisfies ActionSuccessObject;
    }
  }

  // Use typed data validator
  const action5 = useAction5();
  if (action5.value) {
    if (action5.value.failed) {
      action5.value satisfies { failed: true } & (TypedDataValidatorError | ActionFailedObject);
    } else {
      action5.value satisfies ActionSuccessObject;
    }
  }

  // Use data validator
  const action6 = useAction6();
  if (action6.value) {
    if (action6.value.failed) {
      action6.value satisfies { failed: true } & (DataValidatorError | ActionFailedObject);
    } else {
      action6.value satisfies ActionSuccessObject;
    }
  }

  // No validators
  const action7 = useAction7();
  if (action7.value) {
    if (action7.value.failed) {
      action7.value satisfies { failed: true } & ActionFailedObject;
    } else {
      action7.value satisfies ActionSuccessObject;
    }
  }

  // No validators, with action id
  const action8 = useAction7();
  if (action8.value) {
    if (action8.value.failed) {
      action8.value satisfies { failed: true } & ActionFailedObject;
    } else {
      action8.value satisfies ActionSuccessObject;
    }
  }

  return (
    <div>
      <h1>Validated</h1>
      {loader.value.failed ? (
        <div>
          <p>Failed</p>
          <p>{loader.value.message}</p>
        </div>
      ) : (
        <div>
          <p>Success</p>
          <p>{loader.value.stuff}</p>
        </div>
      )}
    </div>
  );
});
