<template>
  <div class="welcome">
    <p><!--
      -->ここでは、サインアップを行います。<!--
      -->アカウントは、端末に1つのものではなく、IDとパスワードでどんな端末でも使いまわすことが出来ます。
    </p>
  </div>

  <form novalidate @submit="submit">
    <Input
      label="ユーザーID"
      autocomplete="username"
      v-model="userid"
    >
      <span
        class="input-issue"
        v-if="useridIssue"
      >
        <Icon icon="material-symbols:error-outline-rounded" />
        {{ useridIssue.message }}
      </span>
    </Input>

    <Input
      label="メールアドレス"
      type="email"
      autocomplete="email"
      v-model="email"
    >
      <span
        class="input-issue"
        v-if="emailIssue"
      >
        <Icon icon="material-symbols:error-outline-rounded" />
        {{ emailIssue.message }}
      </span>
    </Input>

    <InputPassword
      label="パスワード"
      v-model="password"
    >
      <span
        class="input-issue"
        v-if="passwordIssue"
      >
        <Icon icon="material-symbols:error-outline-rounded" />
        {{ passwordIssue.message }}
      </span>

      <span
        class="input-issue password-strength"
        v-if="passwordStrength.message"
      >
        <Icon :icon="passwordStrength.icon" />
        {{ passwordStrength.message }}
      </span>
    </InputPassword>

    <Button
      name="サインアップ"
      type="submit"
      color="accent"
      :disabled="!result.success || isProcessing"
    />

    <RouterLink to="/signin">アカウントをお持ちですか？</RouterLink>
  </form>
</template>

<style scoped>
.welcome {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-bottom: 1.5rem;
}

form {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 30rem;
}

.input-issue {
  display: flex;
  gap: 0.25rem;
  font-size: 0.85rem;
  color: var(--error-color);
  user-select: none;
  -webkit-user-select: none;
}

.input-issue svg {
  font-size: 1rem;
  margin: auto 0;
}

.password-strength {
  color: v-bind(passwordStrengthColor);
}
</style>

<script lang="ts" setup>
import { serverInfo, reloadServerInfo } from "@/lib/account";
import { useRouter } from "vue-router";
import Input from "@/components/Input.vue";
import Button from "@/components/Button.vue";
import { ref } from "vue";
import z from "zod/v3";
import { computed } from "vue";
import zxcvbn from "zxcvbn";
import { createModal } from "@/lib/modal";
import Loading from "@/components/Modal/Loading.vue";
import ErrorModal from "@/components/Modal/Error.vue";
import Success from "@/components/Modal/Success.vue";
import InputPassword from "@/components/InputPassword.vue";
import client from "@/lib/client";
import { getIssueFromPath } from "@/lib/validation";
import { Icon } from "@iconify/vue";

const router = useRouter();
const isProcessing = ref<boolean>(false);

if (!serverInfo.value?.success) {
  throw new Error("サーバー情報の取得に失敗しました。");
}

if (!serverInfo.value.isInitialized) {
  router.replace("/setup/initialization");
}

const userid = ref<string>("");
const email = ref<string>("");
const password = ref<string>("");
const useridIssue = computed(() => getIssueFromPath("userid", result.value));
const emailIssue = computed(() => getIssueFromPath("email", result.value));
const passwordIssue = computed(() => getIssueFromPath("password", result.value));

const passwordScores = [
  ["危険なパスワード", "error-outline-rounded", "var(--error-color)"],
  ["推測可能なパスワード", "warning-rounded", "var(--warn-color)"],
  ["推測しやすいパスワード", "warning-rounded", "var(--warn-color)"],
  ["安全なパスワード", "check-circle", "var(--success-color)"],
  ["強力なパスワード", "check-circle", "var(--success-color)"],
];
const passwordStrength = computed(() => {
  const evaluation = zxcvbn(password.value);
  return {
    message: passwordScores[evaluation.score]![0],
    score: evaluation.score,
    icon: "material-symbols:" + passwordScores[evaluation.score]![1],
    color: passwordScores[evaluation.score]![2],
  }
});
const passwordStrengthColor = computed(() => passwordStrength.value.color);

const EmailRegex = /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:([0-9]{1,3}\.){3}[0-9]{1,3})\])$/i;
const schema = z.object({
  userid: z.string({ message: "文字列で入力してください。" })
    .trim().min(3, "3文字以上で入力してください。")
    .max(20, "20文字以内で入力してください。"),
  email: z.string({ message: "文字列で入力してください。" })
    .trim().min(6, "6文字以上で入力してください。")
    .max(254, "254文字以内で入力してください。")
    .regex(EmailRegex, "形式が異なります。"),
  password: z.string({ message: "文字列で入力してください。" })
    .trim().min(8, "8文字以上で入力してください。"),
});

const result = computed(() => schema.safeParse({
  userid: userid.value,
  email: email.value,
  password: password.value,
}));

const submit = async (e: Event) => {
  e.preventDefault();
  isProcessing.value = true;

  const closeLoadingModal = createModal({
    component: Loading,
  });

  if (!result.value.success) {
    const messages = result.value.error.issues.map(issue => issue.message);

    closeLoadingModal();

    return createModal({
      component: ErrorModal,
      onClose: () => isProcessing.value = false,
      props: {
        error: `不正な入力です。<br>${messages.join("<br>")}`,
        canClose: true,
      },
    });
  }

  const response = await client.value.request("setup/create-admin", result.value.data);

  if (!response.success) {
    closeLoadingModal();

    return createModal({
      component: ErrorModal,
      onClose: () => isProcessing.value = false,
      props: {
        error: response.error.message,
        canClose: true,
      },
    });
  }

  closeLoadingModal();

  return createModal({
    component: Success,
    onClose: async () => {
      isProcessing.value = false;
      await reloadServerInfo();
      router.push("/signin");
    }
  });
}
</script>