<template>
  <div
    :class='[
      "w-full", "h-full", "pt-10",
      "flex", "justify-center",
    ]'
  >
    <div :class='[
      "w-130", "h-fit", "flex", "flex-col", "p-6",
      "bg-white", "text-black",
      "dark:bg-neutral-600", "dark:text-white",
      "shadow-sm", "rounded-2xl",
    ]'>
      <h1 class="font-bold">サインイン</h1>
      <SmallText v-html="
        `uwuzu ${sprtVerTxt}に対応しています。<br />
        ただし、最新版でない場合一部の機能が制限される可能性があります。`
      "/>
      
      <hr class="my-3" />
      
      <form class="flex flex-col gap-2" @submit="onSubmit">
        <div class="flex flex-col">
          <label for="origin">オリジン(必須)</label>
          <InputText
            type="url"
            placeholder="https://uwuzu.net"
            id="origin"
            v-model="origin"
            :disabled="isSubmitting"
          />
          <SmallText>
            サインインするサーバーのオリジンを入力してください。 
          </SmallText>
        </div>
        
        <hr class="w-[90%] m-auto" />
        
        <details>
          <summary class="select-none cursor-pointer">その他のオプション</summary>
          <div class="flex flex-col mt-1">
            <label for="token">APIトークン(任意)</label>
            <InputText
              type="password"
              placeholder="ABCD123456789"
              id="token"
              v-model="token"
              :disabled="isSubmitting"
            />
            <div class="text-yellow-200">
              通常は必要ありません。
            </div>
            <SmallText>
              サインインするアカウントのAPIトークンを入力してください。権限の確認は行いません。<br />
              以下の権限が必要です。
            </SmallText>
            <ul>
              <li class="list-disc list-inside" v-for="scope in requiredScopes">
                {{ scope }}
              </li>
            </ul>
          </div>
        </details>
        
        <Button
          type="submit"
          class="m-auto"
          :disabled="isSubmitting"
        >
          <span v-if="isSubmitting">サインイン中...</span>
          <span v-else>サインイン</span>
        </Button>
      </form>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { useHead } from "@vueuse/head";
import { ref } from "vue";
import { z } from "zod/v3";
import { v4 as UUID } from "uuid";
import { useRouter } from "vue-router";
import Database from "@/lib/db";
import { isSignin } from "@/lib/account";
import useAPI from "@/lib/api";
import { isVersionAvailable } from "@/lib/version";
import SmallText from "@/components/SmallText.vue";
import InputText from "@/components/InputText.vue";
import Button from "@/components/Button.vue";

useHead({
  title: "サインイン | Clean Follow uwuzu",
});

if (await isSignin(new Database())) {
  useRouter().replace("/");
}

const emit = defineEmits(["failed"]);
const sprtVer = __CONFIG.uwuzu.supportedVersion;
const sprtVerTxt = `v${sprtVer.min}${
  sprtVer.min !== sprtVer.max
    ? `からv${sprtVer.max}`
    : ''
}`;
const requiredScopes = __CONFIG.uwuzu.requiredScopes;
const origin = ref<string>("");
const token = ref<string>("");
const isSubmitting = ref<boolean>(false);

const onSubmit = async (e: Event) => {
  e.preventDefault();
  isSubmitting.value = true;

  const result = z.object({
    origin: z.string({
      invalid_type_error: "オリジンが文字列ではありません",
    })
      .min(1, "オリジンが入力されていません")
      .refine(value => {
        if (value.length === 0)
          return true;
        
        try {
          const url = new URL(value);
          return url.origin === value;
        } catch {
          return false;
        }
      }, "オリジンが有効ではありません"),
    token: z.string({
      invalid_type_error: "APIトークンが文字列ではありません",
    })
      .min(1, "APIトークンが入力されていません")
      .length(64, "APIトークンは64文字です")
      .or(z.literal("")),
  }).safeParse({
    origin: origin.value,
    token: token.value,
  });

  if (!result.success) {
    emit("failed", result.error.errors.map(err => err.message).join("\n"));
    return;
  }
  
  const serverinfo = await useAPI(result.data.origin, "/serverinfo-api", {
    method: "POST",
    cache: "no-store",
  });
  
  if (serverinfo.software.name !== "uwuzu") {
    throw new Error("サーバーがuwuzuではありません。");
  }
  
  if (!isVersionAvailable({
    current: serverinfo.software.version,
    min: sprtVer.min,
    max: sprtVer.max,
  })) {
    throw "サーバーのバージョンが対象外です。";
  }
  
  if (result.data.token.length === 64) {
    const callback = new URL("/signin/callback", window.location.origin);
    callback.searchParams.set("type", "token");
    callback.searchParams.set("origin", result.data.origin);
    callback.searchParams.set("session", result.data.token);
    window.location.href = callback.toString();
    return;
  }
  
  const session = UUID();
  const callback = new URL("/signin/callback", window.location.origin);
  callback.searchParams.set("type", "auth");
  callback.searchParams.set("origin", result.data.origin);
  callback.searchParams.set("session", session);
  const authURL = new URL("/api/auth", result.data.origin);
  authURL.searchParams.set("session", session);
  authURL.searchParams.set("scope", requiredScopes.join(","));
  authURL.searchParams.set("callback", callback.toString());
  authURL.searchParams.set("client", "Clean Follow uwuzu");
  authURL.searchParams.set("about", "uwuzu向けのフォロー整理アプリです。");
  authURL.searchParams.set("icon", new URL("/cfu.svg", window.location.origin).toString());
  window.location.href = authURL.toString();
  return;
};
</script>
