import { setTimeout as sleep } from "node:timers/promises";

import {
  antiDetectPause,
  ensureSlideVerification,
  humanClick,
  randomBetween,
  waitForManualVerificationIfNeeded,
} from "./human.js";

const LOGIN_URL = "https://login.taobao.com/member/login.jhtml?style=tao_custom&from=1688web";
const SEARCH_HOME_URL = "https://www.1688.com/";
const LOGIN_SUCCESS_GRACE_AFTER_VERIFICATION_MS = 30000;
const VERIFICATION_TEXT_PATTERN = /验证码拦截|拖动下方滑块完成验证|请按住滑块|通过验证以确保正常访问|验证失败|二次验证|拖动到最右边|滑动验证|短信验证码|手机验证码|验证码已发送|请输入.{0,12}验证码|输入.{0,12}验证码|校验码|安全验证.{0,20}验证码|身份验证.{0,20}验证码|验证码.{0,12}(?:重新发送|已发送)|x5step=1|\/punish\b/i;

function normalizeText(value) {
  return String(value ?? "").replace(/\s+/g, " ").trim();
}

export function is1688LoginUrl(url) {
  const value = String(url ?? "");
  return value.includes("login.taobao.com") || value.includes("login.1688.com");
}

async function hasLoginSession(context) {
  const cookies = await context.cookies([SEARCH_HOME_URL, "https://login.taobao.com"]);
  return cookies.some((cookie) => cookie.name === "_m_h5_tk" || cookie.name === "cookie2" || cookie.name === "xman_us_t");
}

async function pageLooksLikeVerification(page) {
  if (!page || page.isClosed()) {
    return false;
  }

  const pageUrl = String(page.url?.() ?? "");
  if (VERIFICATION_TEXT_PATTERN.test(pageUrl)) {
    return true;
  }

  const bodyText = await page.locator("body").innerText({ timeout: 1200 }).catch(async () => (
    page.evaluate(() => document.body?.innerText ?? "").catch(() => "")
  ));

  return VERIFICATION_TEXT_PATTERN.test(normalizeText(bodyText));
}

async function settleSlideVerification(page, logPrefix = "[login-preflight][验证码]") {
  const resolved = await ensureSlideVerification(page, { logPrefix }).catch(() => false);
  if (resolved) {
    await page.waitForLoadState("domcontentloaded", { timeout: 5000 }).catch(() => {});
  }

  await waitForManualVerificationIfNeeded(page).catch(() => false);
  return !(await pageLooksLikeVerification(page));
}

async function clickPasswordTab(page) {
  const tab = page.getByText("密码登录").first();
  if (await tab.isVisible().catch(() => false)) {
    await humanClick(page, tab).catch(() => tab.click({ delay: randomBetween(60, 180) }).catch(() => {}));
    await antiDetectPause(600, 1200);
  }
}

async function slowType(page, selector, value) {
  const normalized = normalizeText(value);
  if (!normalized) {
    return;
  }

  const field = page.locator(selector).first();
  await field.waitFor({ state: "visible", timeout: 15000 });
  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 normalized) {
    await page.keyboard.type(char, { delay: randomBetween(90, 220) });
    await sleep(randomBetween(30, 120));
  }
}

async function clickLoginButton(page) {
  const candidates = [
    page.getByRole("button", { name: /登录|登 录|立即登录/ }).first(),
    page.locator("button[type='submit']").first(),
    page.locator("input[type='submit']").first(),
    page.locator(".fm-button.fm-submit").first(),
    page.locator(".password-login").first(),
  ];

  for (const candidate of candidates) {
    if ((await candidate.count().catch(() => 0)) === 0) {
      continue;
    }
    if (!(await candidate.isVisible().catch(() => false))) {
      continue;
    }

    await humanClick(page, candidate).catch(async () => {
      await candidate.click({ delay: randomBetween(60, 180) }).catch(async () => {
        await page.keyboard.press("Enter").catch(() => {});
      });
    });
    return;
  }

  await page.keyboard.press("Enter").catch(() => {});
}

async function waitForLoginSuccess(page, context, timeoutMs) {
  let deadlineAt = Date.now() + timeoutMs;

  while (Date.now() < deadlineAt) {
    const verificationBeforeSettle = await pageLooksLikeVerification(page).catch(() => false);
    const settleStartedAt = Date.now();
    const currentPageClear = await settleSlideVerification(page);
    const waitedForVerificationMs = Date.now() - settleStartedAt;
    if (currentPageClear && (verificationBeforeSettle || waitedForVerificationMs > 5000)) {
      deadlineAt = Math.max(deadlineAt, Date.now() + LOGIN_SUCCESS_GRACE_AFTER_VERIFICATION_MS);
    }

    if (currentPageClear && !is1688LoginUrl(page.url()) && await hasLoginSession(context)) {
      return page;
    }

    for (const candidate of context.pages()) {
      if (!is1688LoginUrl(candidate.url()) && (candidate.url().includes("1688.com") || candidate.url().includes("taobao.com"))) {
        const candidateClear = candidate === page ? currentPageClear : await settleSlideVerification(candidate);
        if (candidateClear && await hasLoginSession(context)) {
          if (candidate !== page) {
            await candidate.bringToFront().catch(() => {});
          }
          return candidate;
        }
      }
    }

    await sleep(1500);
  }

  return null;
}

async function detectFailureReason(page) {
  const bodyText = await page.locator("body").innerText().catch(() => "");

  if (/短信验证码|手机验证码|验证码已发送|请输入.{0,12}验证码|输入.{0,12}验证码|校验码|验证码.{0,12}(?:重新发送|已发送)/.test(bodyText)) {
    return "搜索前登录态预热暂停：当前页面需要手机短信验证码";
  }

  if (/验证码|滑动|二次验证|验证失败/.test(bodyText)) {
    return "搜索前登录态预热失败：当前页面需要验证码或二次验证";
  }

  if (/账号|密码.*错误|登录失败|账户异常/.test(bodyText)) {
    return "搜索前登录态预热失败：请检查 1688 账户名/邮箱/手机号或密码是否正确";
  }

  return "搜索前登录态预热失败：未获得有效的 1688 登录态";
}

function pickReusablePage(context) {
  return context.pages().find((page) => !page.isClosed() && page.url().includes("1688.com"))
    ?? context.pages().find((page) => !page.isClosed())
    ?? null;
}

export async function ensure1688LoggedIn(context, options = {}) {
  const timeoutMs = Number.isInteger(options.timeoutMs) && options.timeoutMs > 0 ? options.timeoutMs : 90000;
  const accountName = normalizeText(options.accountName ?? process.env.LOGIN_1688_USER);
  const password = normalizeText(options.password ?? process.env.LOGIN_1688_PASS);
  const page = pickReusablePage(context) ?? await context.newPage();

  await page.goto(SEARCH_HOME_URL, { waitUntil: "domcontentloaded", timeout: timeoutMs }).catch(() => {});
  const homePageClear = await settleSlideVerification(page);
  await antiDetectPause(800, 1500);

  if (homePageClear && !is1688LoginUrl(page.url()) && await hasLoginSession(context)) {
    return { ok: true, page, status: "existing_session", reason: "" };
  }

  if (!accountName || !password) {
    return {
      ok: false,
      page,
      status: "missing_credentials",
      reason: "搜索前登录态预热失败：未提供 1688 账号或密码",
    };
  }

  await page.goto(LOGIN_URL, { waitUntil: "domcontentloaded", timeout: timeoutMs });
  await settleSlideVerification(page);
  await antiDetectPause();
  await clickPasswordTab(page);
  await slowType(page, "#fm-login-id", accountName);
  await antiDetectPause(800, 1500);
  await slowType(page, "#fm-login-password", password);
  await antiDetectPause(800, 1500);
  await clickLoginButton(page);
  await antiDetectPause(1200, 2200);

  const loggedInPage = await waitForLoginSuccess(page, context, timeoutMs);
  if (loggedInPage) {
    await settleSlideVerification(loggedInPage);
    return { ok: true, page: loggedInPage, status: "logged_in", reason: "" };
  }

  return {
    ok: false,
    page,
    status: "login_failed",
    reason: await detectFailureReason(page),
  };
}
