import type { Page } from "playwright";
import {
  parseMothershipQuoteUrls,
  validateMothershipQuoteUrls,
} from "@/lib/rpa/env";
import {
  RPA_PAGE_GOTO_TIMEOUT_MS,
  RPA_SESSION_WIDGET_TIMEOUT_MS,
} from "@/lib/constants/rpa";
import { RpaError } from "@/modules/rpa/errors";
import {
  hasMothershipCredentials,
  mapUrlToErrorCode,
} from "@/modules/rpa/error-mapper";
import {
  getStorageStateForContext,
  invalidateStorageState,
  persistContext,
} from "@/lib/rpa/storage-state";
import { waitForQuoteWidgetReady } from "@/workers/rpa/address-side";
import { stabilizeQuoteLandingPage } from "@/workers/rpa/page-prep";

const LOGIN_URL_PATTERNS = ["/login", "/sign-in", "/signin"];
const CLOUDFLARE_SELECTORS =
  "#challenge-running, .cf-browser-verification, iframe[src*='challenges.cloudflare.com']";
const HUMAN_ENTRY_CLICK_SPECS = [
  'role=link[name=/get.*quote/i]',
  'role=button[name=/get.*quote/i]',
  "text=Get a Quote",
  "text=Get freight quote",
  "text=获取货运报价",
];

export type QuotePageOpenOptions = {
  /** 复用 quote_session storageState：跳过首页预热、缩短 widget 等待 */
  reuseSession?: boolean;
};

export type QuotePageAdapter = {
  resolveQuoteEntry(
    page: Page,
    options?: QuotePageOpenOptions,
  ): Promise<{ activeUrl: string }>;
  preCheck(page: Page, options?: QuotePageOpenOptions): Promise<boolean>;
  isLoginWithoutCredentials(page: Page): boolean;
};

function isLoginUrl(url: string): boolean {
  const lower = url.toLowerCase();
  return LOGIN_URL_PATTERNS.some((pattern) => lower.includes(pattern));
}

function readPageGotoTimeoutMs(): number {
  const raw = process.env.RPA_PAGE_GOTO_TIMEOUT_MS?.trim();
  if (!raw) {
    return RPA_PAGE_GOTO_TIMEOUT_MS;
  }
  const parsed = Number(raw);
  return Number.isFinite(parsed) && parsed >= 10_000
    ? parsed
    : RPA_PAGE_GOTO_TIMEOUT_MS;
}

/** domcontentloaded 超时后回退 commit/load，应对慢网或长连接阻塞 */
async function openQuoteEntryUrl(page: Page, url: string): Promise<void> {
  const timeout = readPageGotoTimeoutMs();
  const strategies: Array<"domcontentloaded" | "commit" | "load"> = [
    "domcontentloaded",
    "commit",
    "load",
  ];
  let lastError: Error | undefined;

  for (const waitUntil of strategies) {
    try {
      await page.goto(url, { waitUntil, timeout });
      return;
    } catch (error) {
      lastError = error instanceof Error ? error : new Error(String(error));
    }
  }

  throw lastError ?? new RpaError("QUOTE_ENTRY_UNAVAILABLE", `无法打开 ${url}`, {
    retryable: false,
  });
}

/** 模拟真人：首页预热 → 点击报价入口，携带 Referer/Cookie */
async function runHumanEntryWarmup(page: Page): Promise<void> {
  if (process.env.RPA_HUMAN_ENTRY_FLOW !== "true") {
    return;
  }
  const warmupUrl =
    process.env.RPA_QUOTE_WARMUP_URL?.trim() || "https://www.mothership.com/";
  await openQuoteEntryUrl(page, warmupUrl);
  await page.waitForTimeout(800);

  for (const spec of HUMAN_ENTRY_CLICK_SPECS) {
    const target = page.locator(spec).first();
    const visible = await target.isVisible().catch(() => false);
    if (!visible) {
      continue;
    }
    await target.click({ timeout: 8_000 }).catch(() => undefined);
    await page
      .waitForLoadState("domcontentloaded", { timeout: 10_000 })
      .catch(() => undefined);
    console.log(`[rpa] human-entry: clicked ${spec}`);
    return;
  }
  console.warn("[rpa] human-entry: 未找到报价入口按钮，继续直接打开 URL");
}

export class MothershipQuotePageAdapter implements QuotePageAdapter {
  isLoginWithoutCredentials(page: Page): boolean {
    return isLoginUrl(page.url()) && !hasMothershipCredentials();
  }

  async preCheck(
    page: Page,
    options?: QuotePageOpenOptions,
  ): Promise<boolean> {
    const url = page.url();
    const urlCode = mapUrlToErrorCode(url);

    if (urlCode === "RPA_CAPTCHA") {
      throw new RpaError("RPA_CAPTCHA", "检测到验证码页面", {
        retryable: false,
        pauseWorker: true,
      });
    }

    if (this.isLoginWithoutCredentials(page)) {
      throw new RpaError(
        "STRUCT_CHANGE",
        "login 页且无 Mothership 凭据（匿名入口失效）",
        { retryable: false },
      );
    }

    if (urlCode === "SESSION_EXPIRED") {
      throw new RpaError("SESSION_EXPIRED", "会话已过期，需重登", {
        retryable: true,
      });
    }

    const cfCount = await page.locator(CLOUDFLARE_SELECTORS).count();
    if (cfCount > 0) {
      throw new RpaError("RPA_CAPTCHA", "检测到 Cloudflare 验证", {
        retryable: false,
        pauseWorker: true,
      });
    }

    const bodyText = await page.locator("body").innerText().catch(() => "");
    if (/page not found|404|doesn't exist|has been moved/i.test(bodyText)) {
      throw new RpaError("STRUCT_CHANGE", "报价页 404 或不可达", {
        retryable: false,
      });
    }

    await waitForQuoteWidgetReady(
      page,
      options?.reuseSession ? RPA_SESSION_WIDGET_TIMEOUT_MS : undefined,
    );
    return true;
  }

  async resolveQuoteEntry(
    page: Page,
    options?: QuotePageOpenOptions,
  ): Promise<{ activeUrl: string }> {
    const urls = parseMothershipQuoteUrls(process.env.MOTHERSHIP_QUOTE_URLS);
    const urlErrors = validateMothershipQuoteUrls(urls);
    if (urlErrors.length > 0) {
      throw new RpaError(
        "QUOTE_ENTRY_UNAVAILABLE",
        urlErrors.join("；"),
        { retryable: false },
      );
    }

    const failures: string[] = [];

    if (!options?.reuseSession) {
      await runHumanEntryWarmup(page);
    }

    for (const url of urls) {
      try {
        await openQuoteEntryUrl(page, url);
        await page
          .waitForLoadState("domcontentloaded", { timeout: 10_000 })
          .catch(() => undefined);
        await stabilizeQuoteLandingPage(page);

        if (this.isLoginWithoutCredentials(page)) {
          invalidateStorageState();
          await openQuoteEntryUrl(page, url);
          await stabilizeQuoteLandingPage(page);
          if (this.isLoginWithoutCredentials(page)) {
            throw new RpaError(
              "STRUCT_CHANGE",
              `入口 ${url} 要求登录且无凭据`,
              { retryable: false },
            );
          }
        }

        return { activeUrl: url };
      } catch (error) {
        const message =
          error instanceof Error ? error.message : String(error ?? "unknown");
        failures.push(`${url}: ${message}`);
      }
    }

    throw new RpaError(
      "QUOTE_ENTRY_UNAVAILABLE",
      `全部报价入口不可用：${failures.join(" | ")}（请检查网络/VPN、.rpa/mothership-storage.json 是否有效，或设 RPA_HEADLESS=false 重录登录态）`,
      { retryable: false },
    );
  }
}

export const quotePageAdapter = new MothershipQuotePageAdapter();
