import { mkdir } from "node:fs/promises";
import { existsSync } from "node:fs";
import path from "node:path";
import process from "node:process";
import readline from "node:readline/promises";
import { stdin as input, stdout as output } from "node:process";
import { setTimeout as sleep } from "node:timers/promises";
import { chromium } from "playwright";
import { antiDetectPause, attachVerificationMonitor, randomBetween } from "./human.js";
import { createResolvedSupabaseClient } from "./supabase-client.js";

const ROOT_DIR = process.cwd();

// ── .env 加载 ─────────────────────────────────────────
const envPaths = [
  path.resolve(ROOT_DIR, ".env"),
  path.resolve(ROOT_DIR, "..", ".env"),
];
for (const p of envPaths) {
  if (existsSync(p)) {
    const dotenv = await import("dotenv");
    dotenv.config({ path: p });
    break;
  }
}

const PROFILE_DIR = path.join(ROOT_DIR, ".browser", "1688-profile");
const LOGIN_URL = "https://login.taobao.com/member/login.jhtml?style=tao_custom&from=1688web";
const USERNAME = process.env.LOGIN_1688_USER ?? "";
const PASSWORD = process.env.LOGIN_1688_PASS ?? "";
const LOGIN_CONTEXT_RETRY_LIMIT = 2;

// ── Supabase 客户端（用于回写登录状态）──────────────────
function getSupabase() {
  try {
    return createResolvedSupabaseClient(process.env);
  } catch {
    return null;
  }
}

async function reportLoginStatus(accountName, status, error = null) {
  const supabase = getSupabase();
  if (!supabase || !accountName) return;
  try {
    await supabase
      .from("procurement_accounts_1688")
      .update({
        login_status: status,
        login_error: error,
        login_checked_at: new Date().toISOString(),
      })
      .eq("account_name", accountName);
  } catch (err) {
    console.warn("[login-1688] 写入登录状态失败:", err.message);
  }
}

async function ensureDir(target) {
  await mkdir(target, { recursive: true });
}

async function slowType(page, selector, value) {
  if (!value) {
    return;
  }

  const field = page.locator(selector);
  await field.click();
  await page.keyboard.press("Meta+A").catch(() => {});
  await sleep(randomBetween(60, 140));
  await page.keyboard.press("Backspace").catch(() => {});
  await sleep(randomBetween(80, 180));

  for (const char of value) {
    await page.keyboard.type(char, { delay: randomBetween(90, 220) });
    await sleep(randomBetween(30, 120));
  }
}

function getErrorMessage(error) {
  return error instanceof Error ? error.message : String(error);
}

function isRetriableLoginError(error) {
  return /Page crashed|Target page, context or browser has been closed|Navigation timeout/i.test(getErrorMessage(error));
}

async function createFreshPage(context, page = null) {
  const nextPage = await context.newPage();

  if (page && !page.isClosed()) {
    await page.close().catch(() => {});
  }

  return nextPage;
}

async function gotoWithRetry(context, page, url, options, label, maxAttempts = 3) {
  let currentPage = page;

  for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
    try {
      await currentPage.goto(url, options);
      return currentPage;
    } catch (error) {
      const message = getErrorMessage(error);
      const retriable = isRetriableLoginError(error);

      if (!retriable || attempt >= maxAttempts) {
        throw error;
      }

      console.warn(`[login-1688] ${label} 第 ${attempt}/${maxAttempts} 次导航失败，准备重试: ${message}`);

      currentPage = await createFreshPage(context, currentPage);

      await antiDetectPause(500, 1200);
    }
  }

  return currentPage;
}

async function launchLoginContext() {
  return chromium.launchPersistentContext(PROFILE_DIR, {
    channel: "chrome",
    headless: false,
    locale: "zh-CN",
    viewport: { width: 1440, height: 960 },
    args: ["--disable-blink-features=AutomationControlled"]
  });
}

async function prepareLoginWindow(context) {
  let page = context.pages()[0] ?? (await context.newPage());
  page = await createFreshPage(context, page);
  page = await gotoWithRetry(
    context,
    page,
    LOGIN_URL,
    { waitUntil: "domcontentloaded", timeout: 60_000 },
    "登录页"
  );
  await antiDetectPause();

  const passwordTab = page.getByText("密码登录").first();
  if (await passwordTab.isVisible().catch(() => false)) {
    await passwordTab.click({ delay: randomBetween(60, 180) }).catch(() => {});
    await antiDetectPause();
  }

  await slowType(page, "#fm-login-id", USERNAME);
  await antiDetectPause();
  await slowType(page, "#fm-login-password", PASSWORD);

  return page;
}

async function main() {
  await ensureDir(PROFILE_DIR);

  for (let attempt = 1; attempt <= LOGIN_CONTEXT_RETRY_LIMIT; attempt += 1) {
    let context;
    let verificationMonitor;

    try {
      context = await launchLoginContext();
      verificationMonitor = attachVerificationMonitor(context, { logPrefix: "[login-1688][验证码]" });
      await prepareLoginWindow(context);

      console.log("登录窗口已重新准备好。请在浏览器中完成验证码/登录。");
      console.log(`登录态会持久化保存到: ${PROFILE_DIR}`);
      console.log("完成后回到终端按 Enter，我会关闭浏览器但保留 session。");

      const rl = readline.createInterface({ input, output });

      try {
        await rl.question("");
        console.log("已关闭浏览器并保留 session。");
        await reportLoginStatus(USERNAME, "success");
        return;
      } catch (err) {
        const errorMsg = err?.code === "ABORT_ERR" ? "用户取消了登录操作" : getErrorMessage(err);
        await reportLoginStatus(USERNAME, "failed", errorMsg);
        throw err;
      } finally {
        rl.close();
      }
    } catch (error) {
      const errorMsg = getErrorMessage(error);
      const retriable = isRetriableLoginError(error);

      if (!retriable || attempt >= LOGIN_CONTEXT_RETRY_LIMIT) {
        await reportLoginStatus(USERNAME, "failed", errorMsg);
        throw error;
      }

      console.warn(`[login-1688] 浏览器会话第 ${attempt}/${LOGIN_CONTEXT_RETRY_LIMIT} 次执行失败，将重启浏览器后重试: ${errorMsg}`);
      await antiDetectPause(800, 1500);
    } finally {
      verificationMonitor?.dispose();
      await context?.close().catch(() => {});
    }
  }
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});
