import { getActiveAccountProfile, setActiveAccountForUser } from "@/lib/account-context";
import { prisma } from "@/lib/db";
import { requireSessionUser } from "@/lib/auth/session";
import { humanDelay } from "@/lib/utils";
import { assessComposeReady, dismissBlockingDialogs } from "./compose";
import {
  clearBrowserProfile,
  launchLoginContext,
  launchSessionContext,
  withPage,
} from "./browser";
import type { BrowserContext } from "playwright";
import { withSessionLock } from "./session-lock";

const LOGIN_URL = "https://www.threads.com/login";
const HOME_URL = "https://www.threads.com/";

export class SessionError extends Error {
  constructor(message: string) {
    super(message);
    this.name = "SessionError";
  }
}

export interface ActiveSession {
  id: string;
  username: string | null;
  storageState: string;
}

export async function saveAccountSession(
  accountId: string,
  storageState: string,
  options?: { valid?: boolean; username?: string | null }
) {
  await prisma.account.update({
    where: { id: accountId },
    data: {
      storageState,
      ...(options?.valid !== undefined && { valid: options.valid }),
      ...(options?.username !== undefined && { username: options.username }),
    },
  });
}

async function persistStorageState(accountId: string, storageState: string, valid = true) {
  await saveAccountSession(accountId, storageState, { valid });
}

export async function clearBrowserSession(): Promise<{ cleared: boolean; message: string }> {
  const account = await getActiveAccount();
  const profileResult = await withSessionLock(() => clearBrowserProfile());

  if (account) {
    await saveAccountSession(account.id, "", { valid: false });
    return {
      cleared: true,
      message: "已清除此帳號的瀏覽器 session",
    };
  }

  return profileResult;
}

export async function startLoginFlow(options?: {
  clearSession?: boolean;
}): Promise<{ success: boolean; message: string }> {
  return withSessionLock(async () => {
    if (options?.clearSession !== false) {
      await clearBrowserProfile();
    }

    const context = await launchLoginContext();
    const page = context.pages()[0] ?? (await context.newPage());

    try {
      await page.goto(LOGIN_URL, { waitUntil: "domcontentloaded", timeout: 60000 });

      try {
        await page.waitForURL(
          (url) =>
            url.hostname.includes("threads") &&
            !url.pathname.includes("/login") &&
            !url.hostname.includes("instagram"),
          { timeout: 300000 }
        );
      } catch {
        // 可能停在 Instagram 授權頁，繼續等待使用者完成
      }

      const deadline = Date.now() + 300000;
      let compose = await assessComposeReady(page);
      while (!compose.ready && Date.now() < deadline) {
        if (page.url().includes("instagram.com")) {
          await page.waitForTimeout(2000);
        } else {
          await page.goto(HOME_URL, { waitUntil: "domcontentloaded", timeout: 45000 }).catch(() => undefined);
          await humanDelay(1500, 2500);
          await dismissBlockingDialogs(page);
          compose = await assessComposeReady(page);
        }
        if (!compose.ready) await page.waitForTimeout(2000);
      }

      if (!compose.ready) {
        return {
          success: false,
          message:
            compose.message ??
            "登入逾時。請確認已在瀏覽器完成 Instagram 授權，並看見 Threads 首頁後再試。",
        };
      }

      await dismissBlockingDialogs(page);
      compose = await assessComposeReady(page);
      if (!compose.ready) {
        return {
          success: false,
          message:
            compose.message ??
            "登入未完成，請在瀏覽器內完成 Instagram 授權後再試一次",
        };
      }

      const storageState = JSON.stringify(await context.storageState());
      const username = await extractUsername(page);

      const user = await requireSessionUser();
      const active = await getActiveAccountProfile();
      const existing =
        active ??
        (username
          ? await prisma.account.findFirst({ where: { userId: user.id, username } })
          : null);

      const account = existing
        ? await prisma.account.update({
            where: { id: existing.id },
            data: {
              username,
              displayName: existing.displayName ?? username ?? undefined,
              storageState,
              valid: true,
            },
          })
        : await prisma.account.create({
            data: {
              userId: user.id,
              username,
              displayName: username ?? "Threads 帳號",
              storageState,
              valid: true,
            },
          });

      await setActiveAccountForUser(user.id, account.id);

      await saveAccountSession(account.id, storageState, { valid: true, username });
      return { success: true, message: username ? `已登入：@${username}` : "登入成功" };
    } finally {
      await context.close();
    }
  });
}

async function extractUsername(page: import("playwright").Page): Promise<string | null> {
  try {
    const profileLink = page.locator('a[href*="/@"]').first();
    const href = await profileLink.getAttribute("href", { timeout: 5000 });
    if (!href) return null;
    const match = href.match(/@([^/?]+)/);
    return match?.[1] ?? null;
  } catch {
    return null;
  }
}

export async function getActiveAccount() {
  return getActiveAccountProfile();
}

export async function refreshSession(account?: {
  id: string;
  username: string | null;
  storageState: string;
}): Promise<{
  valid: boolean;
  username: string | null;
  storageState: string;
  message: string;
  refreshed: boolean;
}> {
  const current = account ?? (await getActiveAccount());
  if (!current) {
    return {
      valid: false,
      username: null,
      storageState: "",
      message: "尚未登入 Threads",
      refreshed: false,
    };
  }

  return withSessionLock(async () => {
    let context: BrowserContext;
    try {
      context = await launchSessionContext({ storageState: current.storageState });
    } catch (error) {
      await saveAccountSession(current.id, current.storageState, { valid: false });
      return {
        valid: false,
        username: current.username,
        storageState: current.storageState,
        refreshed: false,
        message: error instanceof Error ? error.message : "無法啟動瀏覽器，請稍後再試",
      };
    }
    try {
      const page = context.pages()[0] ?? (await context.newPage());
      await page.goto(HOME_URL, { waitUntil: "domcontentloaded", timeout: 45000 });
      await humanDelay(1200, 2200);

      await dismissBlockingDialogs(page);
      const compose = await assessComposeReady(page);
      const valid = compose.ready;
      const username = valid ? (await extractUsername(page)) ?? current.username : current.username;
      const storageState = JSON.stringify(await context.storageState());

      await saveAccountSession(current.id, storageState, { valid, username });

      return {
        valid,
        username,
        storageState,
        refreshed: true,
        message: valid
          ? "Session 已自動更新，可正常發文"
          : (compose.message ?? "Session 已失效，請重新登入"),
      };
    } catch (error) {
      await saveAccountSession(current.id, current.storageState, { valid: false });
      const message = error instanceof Error ? error.message : "更新 session 失敗";
      return {
        valid: false,
        username: current.username,
        storageState: current.storageState,
        refreshed: false,
        message,
      };
    } finally {
      await context.close();
    }
  });
}

export async function ensureActiveSession(): Promise<ActiveSession> {
  const account = await getActiveAccount();
  if (!account) {
    throw new SessionError("尚未登入 Threads，請到設定頁登入");
  }
  if (!account.storageState) {
    throw new SessionError("目前經營帳號尚未登入 Threads，請到設定頁登入此帳號");
  }

  const refreshed = await refreshSession(account);
  if (!refreshed.valid) {
    throw new SessionError(refreshed.message || "Threads session 已失效，請到設定頁重新登入");
  }

  return {
    id: account.id,
    username: refreshed.username,
    storageState: refreshed.storageState,
  };
}

export function browserSessionOptions(session: ActiveSession) {
  return {
    accountId: session.id,
    storageState: session.storageState,
    onSessionPersisted: (storageState: string) => persistStorageState(session.id, storageState),
  };
}

export function accountHasStoredSession(account: { storageState: string } | null): boolean {
  return !!account?.storageState && account.storageState.length > 2;
}

/** 讀取 DB 已儲存的同步狀態，不啟動瀏覽器驗證（避免每次進頁面都把「已同步」洗成未同步）。 */
export async function getStoredSessionStatus(): Promise<{
  synced: boolean;
  valid: boolean;
  username?: string | null;
  message: string;
}> {
  const account = await getActiveAccount();
  if (!account) {
    return { synced: false, valid: false, message: "尚未選擇經營帳號" };
  }

  if (!accountHasStoredSession(account)) {
    return {
      synced: false,
      valid: false,
      username: account.username,
      message: "尚未同步 — 請在 Chrome 登入 threads.com 後按「從 Chrome 同步」",
    };
  }

  return {
    synced: true,
    valid: true,
    username: account.username,
    message: account.username
      ? `已同步 · @${account.username}`
      : "已同步到 server（session 已儲存）",
  };
}

/** 啟動瀏覽器實際驗證並更新 session（用於發文/海巡前，不作為 UI 狀態來源）。 */
export async function checkSessionValid(): Promise<{
  valid: boolean;
  username?: string | null;
  message: string;
  refreshed?: boolean;
}> {
  const account = await getActiveAccount();
  if (!account) {
    return { valid: false, message: "尚未登入 Threads" };
  }
  if (!accountHasStoredSession(account)) {
    return { valid: false, username: account.username, message: "目前經營帳號尚未同步 Threads session" };
  }

  const result = await refreshSession(account);
  return {
    valid: result.valid,
    username: result.username,
    message: result.message,
    refreshed: result.refreshed,
  };
}

export async function probeSession(storageState: string): Promise<boolean> {
  return withPage(
    storageState,
    async (page) => {
      await page.goto(HOME_URL, { waitUntil: "domcontentloaded", timeout: 30000 });
      await humanDelay(1200, 2000);
      return !page.url().includes("/login");
    },
    { persistSession: false }
  );
}
