import { randomUUID } from "node:crypto";
import { jwt } from "@elysiajs/jwt";
import { Elysia, t } from "elysia";
import { BaseHtml } from "../components/base";
import { Header } from "../components/header";
import { LanguageSelector } from "../components/languageSelector";
import { ThemeToggle } from "../components/themeToggle";
import db from "../db/db";
import { User } from "../db/types";
import {
  ACCOUNT_REGISTRATION,
  ALLOW_UNAUTHENTICATED,
  HIDE_HISTORY,
  HTTP_ALLOWED,
  TRUST_PROXY,
  WEBROOT,
} from "../helpers/env";
import { localeService } from "../i18n/service";

export let FIRST_RUN = db.query("SELECT * FROM users").get() === null || false;

// ==============================================================================
// Cookie 設定輔助函數
// ==============================================================================
// 解決遠端部署時登入失敗的問題：
// 1. sameSite: "lax" - 允許導航時傳送 Cookie（strict 會阻擋）
// 2. path: WEBROOT || "/" - 確保 Cookie 覆蓋整個應用
// 3. secure: 考慮 TRUST_PROXY 設定
// ==============================================================================
function getCookieOptions() {
  return {
    httpOnly: true,
    secure: !HTTP_ALLOWED && !TRUST_PROXY ? true : false,
    maxAge: 60 * 60 * 24 * 7, // 7 days
    sameSite: "lax" as const,
    path: WEBROOT || "/",
  };
}

export const userService = new Elysia({ name: "user/service" })
  .use(
    jwt({
      name: "jwt",
      schema: t.Object({
        id: t.String(),
      }),
      secret: process.env.JWT_SECRET ?? randomUUID(),
      exp: "7d",
    }),
  )
  .model({
    signIn: t.Object({
      email: t.String(),
      password: t.String(),
    }),
    session: t.Cookie({
      auth: t.String(),
      jobId: t.Optional(t.String()),
    }),
    optionalSession: t.Cookie({
      auth: t.Optional(t.String()),
      jobId: t.Optional(t.String()),
    }),
  })
  .macro("auth", {
    cookie: "session",
    async resolve({ status, jwt, cookie: { auth } }) {
      if (!auth.value) {
        return status(401, {
          success: false,
          message: "Unauthorized",
        });
      }
      const user = await jwt.verify(auth.value);
      if (!user) {
        return status(401, {
          success: false,
          message: "Unauthorized",
        });
      }
      return {
        success: true,
        user,
      };
    },
  });

export const user = new Elysia()
  .use(userService)
  .use(localeService)
  .get("/setup", ({ redirect, locale, t }) => {
    if (!FIRST_RUN) {
      return redirect(`${WEBROOT}/login`, 302);
    }

    return (
      <BaseHtml title="ConvertX-CN | Setup" webroot={WEBROOT} locale={locale}>
        <>
          <header class="w-full p-4">
            <nav
              class={`
                mx-auto flex max-w-4xl items-center justify-between rounded-sm bg-neutral-900 p-4
              `}
            >
              <strong>ConvertX-CN</strong>
              <div class="flex items-center gap-4">
                <ThemeToggle locale={locale} t={t} />
                <LanguageSelector currentLocale={locale} webroot={WEBROOT} t={t} />
              </div>
            </nav>
          </header>
          <main
            class={`
              mx-auto w-full max-w-4xl flex-1 px-2
              sm:px-4
            `}
          >
            <h1 class="my-8 text-3xl" safe>
              {t("setup", "welcome")}
            </h1>
            <article class="article p-0">
              <header class="w-full bg-neutral-800 p-4" safe>
                {t("setup", "createYourAccount")}
              </header>
              <form method="post" action={`${WEBROOT}/register`} class="p-4">
                <fieldset class="mb-4 flex flex-col gap-4">
                  <label class="flex flex-col gap-1">
                    <span safe>{t("auth", "email")}</span>
                    <input
                      type="email"
                      name="email"
                      class="rounded-sm bg-neutral-800 p-3"
                      placeholder={t("auth", "email")}
                      autocomplete="email"
                      required
                    />
                  </label>
                  <label class="flex flex-col gap-1">
                    <span safe>{t("auth", "password")}</span>
                    <input
                      type="password"
                      name="password"
                      class="rounded-sm bg-neutral-800 p-3"
                      placeholder={t("auth", "password")}
                      autocomplete="current-password"
                      required
                    />
                  </label>
                </fieldset>
                <input type="submit" value={t("auth", "createAccount")} class="btn-primary" />
              </form>
              <footer class="p-4">
                <span safe>{t("setup", "reportIssues")}</span>{" "}
                <a
                  class={`
                    text-accent-500 underline
                    hover:text-accent-400
                  `}
                  href="https://github.com/pi-docket/ConvertX-CN"
                  safe
                >
                  {t("setup", "github")}
                </a>
                .
              </footer>
            </article>
          </main>
        </>
      </BaseHtml>
    );
  })
  .get("/register", ({ locale, t }) => {
    // 移除 ACCOUNT_REGISTRATION 限制，讓註冊頁面始終可用
    return (
      <BaseHtml webroot={WEBROOT} title="ConvertX-CN | Register" locale={locale}>
        <>
          <Header
            webroot={WEBROOT}
            accountRegistration={true}
            allowUnauthenticated={ALLOW_UNAUTHENTICATED}
            hideHistory={HIDE_HISTORY}
            locale={locale}
            t={t}
          />
          <main
            class={`
              w-full flex-1 px-2
              sm:px-4
            `}
          >
            <article class="article">
              <form method="post" class="flex flex-col gap-4">
                <fieldset class="mb-4 flex flex-col gap-4">
                  <label class="flex flex-col gap-1">
                    <span safe>{t("auth", "email")}</span>
                    <input
                      type="email"
                      name="email"
                      class="rounded-sm bg-neutral-800 p-3"
                      placeholder={t("auth", "email")}
                      autocomplete="email"
                      required
                    />
                  </label>
                  <label class="flex flex-col gap-1">
                    <span safe>{t("auth", "password")}</span>
                    <input
                      type="password"
                      name="password"
                      class="rounded-sm bg-neutral-800 p-3"
                      placeholder={t("auth", "password")}
                      autocomplete="current-password"
                      required
                    />
                  </label>
                </fieldset>
                <input
                  type="submit"
                  value={t("auth", "registerButton")}
                  class="w-full btn-primary"
                />
              </form>
            </article>
          </main>
        </>
      </BaseHtml>
    );
  })
  .post(
    "/register",
    async ({ body: { email, password }, set, redirect, jwt, cookie: { auth } }) => {
      // 移除 ACCOUNT_REGISTRATION 限制，讓註冊功能始終可用
      if (FIRST_RUN) {
        FIRST_RUN = false;
      }

      const existingUser = await db.query("SELECT * FROM users WHERE email = ?").get(email);
      if (existingUser) {
        set.status = 400;
        return {
          message: "Email already in use.",
        };
      }
      const savedPassword = await Bun.password.hash(password);

      db.query("INSERT INTO users (email, password) VALUES (?, ?)").run(email, savedPassword);

      const user = db.query("SELECT * FROM users WHERE email = ?").as(User).get(email);

      if (!user) {
        set.status = 500;
        return {
          message: "Failed to create user.",
        };
      }

      const accessToken = await jwt.sign({
        id: String(user.id),
      });

      if (!auth) {
        set.status = 500;
        return {
          message: "No auth cookie, perhaps your browser is blocking cookies.",
        };
      }

      // set cookie with proper options for remote deployment
      auth.set({
        value: accessToken,
        ...getCookieOptions(),
      });

      return redirect(`${WEBROOT}/`, 302);
    },
    { body: "signIn" },
  )
  .get(
    "/login",
    async ({ jwt, redirect, cookie: { auth }, locale, t }) => {
      if (FIRST_RUN) {
        return redirect(`${WEBROOT}/setup`, 302);
      }

      // if already logged in, redirect to home
      if (auth?.value) {
        const user = await jwt.verify(auth.value);

        if (user) {
          return redirect(`${WEBROOT}/`, 302);
        }

        auth.remove();
      }

      return (
        <BaseHtml webroot={WEBROOT} title="ConvertX-CN | Login" locale={locale}>
          <>
            <Header
              webroot={WEBROOT}
              accountRegistration={ACCOUNT_REGISTRATION}
              allowUnauthenticated={ALLOW_UNAUTHENTICATED}
              hideHistory={HIDE_HISTORY}
              locale={locale}
              t={t}
            />
            <main
              class={`
                w-full flex-1 px-2
                sm:px-4
              `}
            >
              <article class="article">
                <form method="post" class="flex flex-col gap-4">
                  <fieldset class="mb-4 flex flex-col gap-4">
                    <label class="flex flex-col gap-1">
                      <span safe>{t("auth", "email")}</span>
                      <input
                        type="email"
                        name="email"
                        class="rounded-sm bg-neutral-800 p-3"
                        placeholder={t("auth", "email")}
                        autocomplete="email"
                        required
                      />
                    </label>
                    <label class="flex flex-col gap-1">
                      <span safe>{t("auth", "password")}</span>
                      <input
                        type="password"
                        name="password"
                        class="rounded-sm bg-neutral-800 p-3"
                        placeholder={t("auth", "password")}
                        autocomplete="current-password"
                        required
                      />
                    </label>
                  </fieldset>
                  <div class="flex flex-row gap-4">
                    <a
                      href={`${WEBROOT}/register`}
                      role="button"
                      class="w-full btn-secondary text-center"
                      safe
                    >
                      {t("nav", "register")}
                    </a>
                    <input
                      type="submit"
                      value={t("auth", "loginButton")}
                      class="w-full btn-primary"
                    />
                  </div>
                </form>
              </article>
            </main>
          </>
        </BaseHtml>
      );
    },
    { body: "signIn", cookie: "optionalSession" },
  )
  .post(
    "/login",
    async function handler({ body, set, redirect, jwt, cookie: { auth } }) {
      const existingUser = db.query("SELECT * FROM users WHERE email = ?").as(User).get(body.email);

      if (!existingUser) {
        set.status = 403;
        return {
          message: "Invalid credentials.",
        };
      }

      const validPassword = await Bun.password.verify(body.password, existingUser.password);

      if (!validPassword) {
        set.status = 403;
        return {
          message: "Invalid credentials.",
        };
      }

      const accessToken = await jwt.sign({
        id: String(existingUser.id),
      });

      if (!auth) {
        set.status = 500;
        return {
          message: "No auth cookie, perhaps your browser is blocking cookies.",
        };
      }

      // set cookie with proper options for remote deployment
      auth.set({
        value: accessToken,
        ...getCookieOptions(),
      });

      return redirect(`${WEBROOT}/`, 302);
    },
    { body: "signIn" },
  )
  .get("/logoff", ({ redirect, cookie: { auth } }) => {
    if (auth?.value) {
      auth.remove();
    }

    return redirect(`${WEBROOT}/login`, 302);
  })
  .post("/logoff", ({ redirect, cookie: { auth } }) => {
    if (auth?.value) {
      auth.remove();
    }

    return redirect(`${WEBROOT}/login`, 302);
  })
  .get(
    "/account",
    async ({ user, redirect, locale, t }) => {
      if (!user) {
        return redirect(`${WEBROOT}/`, 302);
      }

      const userData = db.query("SELECT * FROM users WHERE id = ?").as(User).get(user.id);

      if (!userData) {
        return redirect(`${WEBROOT}/`, 302);
      }

      return (
        <BaseHtml webroot={WEBROOT} title="ConvertX-CN | Account" locale={locale}>
          <>
            <Header
              webroot={WEBROOT}
              accountRegistration={ACCOUNT_REGISTRATION}
              allowUnauthenticated={ALLOW_UNAUTHENTICATED}
              hideHistory={HIDE_HISTORY}
              loggedIn
              locale={locale}
              t={t}
            />
            <main
              class={`
                w-full flex-1 px-2
                sm:px-4
              `}
            >
              <article class="article">
                <form method="post" class="flex flex-col gap-4">
                  <fieldset class="mb-4 flex flex-col gap-4">
                    <label class="flex flex-col gap-1">
                      <span safe>{t("auth", "email")}</span>
                      <input
                        type="email"
                        name="email"
                        class="rounded-sm bg-neutral-800 p-3"
                        placeholder={t("auth", "email")}
                        autocomplete="email"
                        value={userData.email}
                        required
                      />
                    </label>
                    <label class="flex flex-col gap-1">
                      <span safe>{t("auth", "newPassword")}</span>
                      <input
                        type="password"
                        name="newPassword"
                        class="rounded-sm bg-neutral-800 p-3"
                        placeholder={t("auth", "password")}
                        autocomplete="new-password"
                      />
                    </label>
                    <label class="flex flex-col gap-1">
                      <span safe>{t("auth", "currentPassword")}</span>
                      <input
                        type="password"
                        name="password"
                        class="rounded-sm bg-neutral-800 p-3"
                        placeholder={t("auth", "password")}
                        autocomplete="current-password"
                        required
                      />
                    </label>
                  </fieldset>
                  <div role="group">
                    <input
                      type="submit"
                      value={t("auth", "updateButton")}
                      class={`w-full btn-primary`}
                    />
                  </div>
                </form>
              </article>
            </main>
          </>
        </BaseHtml>
      );
    },
    {
      auth: true,
    },
  )
  .post(
    "/account",
    async function handler({ body, set, redirect, jwt, cookie: { auth } }) {
      if (!auth?.value) {
        return redirect(`${WEBROOT}/login`, 302);
      }

      const user = await jwt.verify(auth.value);
      if (!user) {
        return redirect(`${WEBROOT}/login`, 302);
      }
      const existingUser = db.query("SELECT * FROM users WHERE id = ?").as(User).get(user.id);

      if (!existingUser) {
        if (auth?.value) {
          auth.remove();
        }
        return redirect(`${WEBROOT}/login`, 302);
      }

      const validPassword = await Bun.password.verify(body.password, existingUser.password);

      if (!validPassword) {
        set.status = 403;
        return {
          message: "Invalid credentials.",
        };
      }

      const fields = [];
      const values = [];

      if (body.email) {
        const existingUser = await db
          .query("SELECT id FROM users WHERE email = ?")
          .as(User)
          .get(body.email);
        if (existingUser && existingUser.id.toString() !== user.id) {
          set.status = 409;
          return { message: "Email already in use." };
        }
        fields.push("email");
        values.push(body.email);
      }
      if (body.newPassword) {
        fields.push("password");
        values.push(await Bun.password.hash(body.newPassword));
      }

      if (fields.length > 0) {
        db.query(
          `UPDATE users SET ${fields.map((field) => `${field}=?`).join(", ")} WHERE id=?`,
        ).run(...values, user.id);
      }

      return redirect(`${WEBROOT}/`, 302);
    },
    {
      body: t.Object({
        email: t.MaybeEmpty(t.String()),
        newPassword: t.MaybeEmpty(t.String()),
        password: t.String(),
      }),
      cookie: "session",
    },
  );
