import { ActionError, defineAction } from 'astro:actions';
import { z } from 'astro:schema';
import { db } from '@db/database.ts';
import { getJavaUuid } from '@util/minecraft.ts';
import { getSetting, SettingKey } from '@util/settings.ts';
import { sendWebhook, WebhookAction } from '@util/webhook.ts';

export const signup = {
  signup: defineAction({
    input: z.object({
      firstname: z.string().trim().min(2),
      lastname: z.string().trim().min(2),
      birthday: z
        .string()
        .date()
        // this will be inaccurate as it is evaluated only once
        .max(Date.now() - 1000 * 60 * 60 * 24 * 365 * 6),
      phone: z.string().trim().nullable(),
      username: z.string().trim(),
      edition: z.enum(['java', 'bedrock']),
      hash: z.string().nullish()
    }),
    handler: async (input) => {
      // check if hash given and if so, if it's valid and nobody has already used it
      if (input.hash) {
        const directSignup = await db.getDirectSignupByHash({ hash: input.hash });

        if (!directSignup) {
          throw new ActionError({
            code: 'NOT_FOUND'
          });
        } else if (directSignup.user) {
          throw new ActionError({
            code: 'CONFLICT'
          });
        }
      }
      // check if signup is allowed
      else if (!(await getSetting(db, SettingKey.SignupEnabled))) {
        throw new ActionError({
          code: 'FORBIDDEN',
          message: 'Die Anmeldung ist derzeit deaktiviert'
        });
      }
      // check if the user were already signed up
      else if (await db.getUserByUsername({ username: input.username })) {
        throw new ActionError({
          code: 'CONFLICT',
          message: 'Du hast dich bereits registriert'
        });
      }

      let uuid = null;
      if (input.edition == 'java') {
        try {
          uuid = await getJavaUuid(input.username);
        } catch (_) {
          throw new ActionError({
            code: 'NOT_FOUND',
            message: `Es wurde kein Minecraft Java Account mit dem Username ${input.username} gefunden`
          });
        }
      }

      await db.transaction(async (tx) => {
        const user = await tx.addUser({
          firstname: input.firstname,
          lastname: input.lastname,
          birthday: input.birthday,
          telephone: input.phone,
          username: input.username,
          edition: input.edition,
          uuid: uuid
        });

        if (input.hash) {
          await tx.setDirectSignupUser({ hash: input.hash, userId: user.id });
        }
      });

      sendWebhook(WebhookAction.Signup, {
        firstname: input.firstname,
        lastname: input.lastname,
        birthday: new Date(input.birthday).toISOString().slice(0, 10),
        telephone: input.phone,
        username: input.username,
        edition: input.edition,
        uuid: uuid
      });
    }
  })
};
