import fs from "node:fs";
import path from "node:path";
import type { Browser, BrowserContext, Page } from "playwright";
import { launchRpaBrowser } from "@/lib/rpa/browser-launch";
import { getPrimaryMothershipQuoteUrl, getRpaBrowserLocale } from "@/lib/rpa/env";
import { resolveQuoteSessionStoragePath } from "@/lib/rpa/quote-session-store";
import { RPA_PAGE_GOTO_TIMEOUT_MS } from "@/lib/constants/rpa";
import {
  getStorageStateForContext,
  invalidateStorageState,
  persistContext,
} from "@/lib/rpa/storage-state";
import { assertRpaSelectorsEnv } from "@/lib/rpa/selectors";
import { RpaError } from "@/modules/rpa/errors";
import { PROVIDER_LOGIN_FAILED_USER_MESSAGE } from "@/modules/rpa/provider-login-message";
import { getEffectiveMothershipLogin } from "@/lib/rpa/mothership-login-context";
import {
  quotePageAdapter,
  type QuotePageAdapter,
} from "@/workers/rpa/quote-page-adapter";
import { releaseAllParkedQuoteSessions } from "@/workers/rpa/parked-quote-session";
import { AUTOCOMPLETE_MONKEY_PATCH_INIT } from "@/workers/rpa/fix-place/recon-helpers";
import {
  P0_PLACE_DIAG_INIT,
  P2_FETCH_HIJACK_INIT,
} from "@/workers/rpa/fix-place/place-diagnostic-init";
import { isPlaceDiagEnabled } from "@/workers/rpa/fix-place/place-diagnostic-probe";
import { isDualAddressPatchEnabled } from "@/lib/rpa/env";
import { DUAL_ADDRESS_PATCH_INIT } from "@/workers/rpa/inject/dual-address-patch-init";

export {
  getStorageStatePath,
  invalidateStorageState,
  persistContext,
  storageStateExists,
} from "@/lib/rpa/storage-state";

const LOGIN_URL_PATTERNS = ["/login", "/sign-in", "/signin"];

let browser: Browser | null = null;
let rpaLockTail: Promise<void> = Promise.resolve();

/** 串行化 Playwright 会话，避免候选/询价双 job 争用 browser 与 storageState */
export async function withRpaSessionLock<T>(
  fn: () => Promise<T>,
): Promise<T> {
  const previous = rpaLockTail;
  let release!: () => void;
  rpaLockTail = new Promise<void>((resolve) => {
    release = resolve;
  });
  await previous;
  try {
    return await fn();
  } finally {
    release();
  }
}

async function launchBrowser(): Promise<Browser> {
  const headless =
    process.env.RPA_HEADED === "true"
      ? false
      : process.env.RPA_HEADLESS !== "false";
  const slowMoRaw = process.env.RPA_SLOW_MO_MS?.trim();
  const slowMo =
    !headless && slowMoRaw && Number.isFinite(Number(slowMoRaw))
      ? Number(slowMoRaw)
      : !headless
        ? 100
        : undefined;

  return launchRpaBrowser({ headless, ...(slowMo !== undefined ? { slowMo } : {}) });
}

function attachNetworkDebug(page: Page): void {
  if (process.env.RPA_NETWORK_DEBUG !== "true") {
    return;
  }
  page.on("request", (req) => {
    console.log(`[rpa-net] >> ${req.method()} ${req.url()}`);
  });
  page.on("response", (res) => {
    console.log(`[rpa-net] << ${res.status()} ${res.url()}`);
  });
}

async function ensureBrowser(): Promise<Browser> {
  if (!browser) {
    browser = await launchBrowser();
  }
  return browser;
}

function isLoginPage(page: Page): boolean {
  const url = page.url().toLowerCase();
  return LOGIN_URL_PATTERNS.some((pattern) => url.includes(pattern));
}

async function loginIfNeeded(page: Page): Promise<void> {
  if (!isLoginPage(page)) {
    return;
  }

  const creds = getEffectiveMothershipLogin();
  if (!creds) {
    throw new RpaError(
      "STRUCT_CHANGE",
      "login 页且无 Mothership 凭据（请配置客户承运商账密或 MOTHERSHIP_EMAIL/PASSWORD）",
      { retryable: false },
    );
  }

  const email = creds.email;
  const password = creds.password;

  const byTestIdEmail = page.getByTestId("auth-email-input");
  if ((await byTestIdEmail.count()) > 0) {
    await byTestIdEmail.fill(email);
    await page.getByTestId("auth-password-input").fill(password);
    await page.getByTestId("auth-log-in-button").click();
  } else {
    const emailSelector =
      process.env.RPA_SELECTOR_LOGIN_EMAIL ??
      'input[type="email"], input[name="email"]';
    const passwordSelector =
      process.env.RPA_SELECTOR_LOGIN_PASSWORD ??
      'input[type="password"], input[name="password"]';
    const submitSelector =
      process.env.RPA_SELECTOR_LOGIN_SUBMIT ??
      'button[type="submit"], button:has-text("Sign in"), button:has-text("Log in")';

    await page.fill(emailSelector, email);
    await page.fill(passwordSelector, password);
    await page.click(submitSelector);
  }
  await page.waitForLoadState("networkidle", { timeout: 20_000 }).catch(() => {
    /* 部分页面无 networkidle */
  });

  if (isLoginPage(page)) {
    throw new RpaError("PROVIDER_LOGIN_FAILED", PROVIDER_LOGIN_FAILED_USER_MESSAGE, {
      retryable: false,
    });
  }
}

export async function createContext(
  b: Browser,
  opts?: { storageStatePath?: string; skipStorageState?: boolean },
): Promise<BrowserContext> {
  const statePath: { storageState?: string } =
    opts?.skipStorageState === true
      ? {}
      : getStorageStateForContext(opts?.storageStatePath);
  const locale = getRpaBrowserLocale();
  const baseOpts = {
    viewport: { width: 1280, height: 900 } as const,
    locale,
    extraHTTPHeaders: { "Accept-Language": `${locale},en;q=0.9` },
    userAgent:
      "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36",
  };
  const context = await b.newContext({ ...baseOpts, ...statePath });
  if (isPlaceDiagEnabled()) {
    await context.addInitScript({ content: P0_PLACE_DIAG_INIT });
    await context.addInitScript({ content: P2_FETCH_HIJACK_INIT });
  } else {
    await context.addInitScript(AUTOCOMPLETE_MONKEY_PATCH_INIT);
  }
  if (isDualAddressPatchEnabled()) {
    await context.addInitScript({ content: DUAL_ADDRESS_PATCH_INIT });
  }
  await context.addInitScript(() => {
    document.documentElement.setAttribute("translate", "no");
    document.documentElement.lang = "en";
    const injectNotranslate = () => {
      const existing = document.querySelector(
        'meta[name="google"][content="notranslate"]',
      );
      if (existing) {
        return;
      }
      const meta = document.createElement("meta");
      meta.name = "google";
      meta.content = "notranslate";
      document.head?.appendChild(meta);
    };
    if (document.head) {
      injectNotranslate();
    } else {
      document.addEventListener("DOMContentLoaded", injectNotranslate, {
        once: true,
      });
    }
  });
  return context;
}

export type OpenQuotePageResult = {
  page: Page;
  context: BrowserContext;
  activeUrl: string;
  reuseSession: boolean;
};

export type OpenQuotePageOptions = {
  /** 询价专用：不加载任何 storageState，并清空页面 storage，避免 MotherShip 货物回填 */
  freshCargoContext?: boolean;
};

export async function openQuotePage(
  adapter: QuotePageAdapter = quotePageAdapter,
  reloginAttempt = false,
  quoteSessionId?: string,
  options?: OpenQuotePageOptions,
): Promise<OpenQuotePageResult> {
  if (reloginAttempt) {
    invalidateStorageState();
    if (browser) {
      await browser.close().catch(() => undefined);
      browser = null;
    }
  }

  const freshCargoContext = options?.freshCargoContext === true;
  const reuseSession =
    !freshCargoContext && Boolean(quoteSessionId?.trim());

  const b = await ensureBrowser();
  let sessionStoragePath: string | null = null;
  if (!freshCargoContext) {
    sessionStoragePath = quoteSessionId
      ? await resolveQuoteSessionStoragePath(quoteSessionId)
      : null;
    if (quoteSessionId && !sessionStoragePath) {
      console.warn(
        `[rpa] quote_session 无效或已过期 id=${quoteSessionId.slice(0, 8)}…，回退默认 storageState`,
      );
    } else if (sessionStoragePath) {
      console.log(
        `[rpa] 复用 quote_session storageState id=${quoteSessionId!.slice(0, 8)}…`,
      );
    }
  } else {
    console.log("[rpa] 询价使用全新浏览器上下文（不复用 storageState）");
  }

  const context = await createContext(
    b,
    freshCargoContext
      ? { skipStorageState: true }
      : { storageStatePath: sessionStoragePath ?? undefined },
  );
  const page = await context.newPage();
  page.setDefaultTimeout(12_000);
  page.setDefaultNavigationTimeout(RPA_PAGE_GOTO_TIMEOUT_MS);
  attachNetworkDebug(page);

  try {
    const { activeUrl } = await adapter.resolveQuoteEntry(page, {
      reuseSession,
    });
    if (freshCargoContext) {
      await page
        .evaluate(() => {
          localStorage.clear();
          sessionStorage.clear();
        })
        .catch(() => undefined);
      console.log("[rpa] 已清空页面 localStorage/sessionStorage");
    }
    await loginIfNeeded(page);
    return { page, context, activeUrl, reuseSession };
  } catch (error) {
    await page.close().catch(() => undefined);
    await context.close().catch(() => undefined);
    throw error;
  }
}

/** @deprecated 兼容旧调用 */
export async function getSession(relogin = false): Promise<BrowserContext> {
  const { context } = await openQuotePage(quotePageAdapter, relogin);
  return context;
}

export async function closeSession(): Promise<void> {
  /* context 按 job 关闭 */
}

export async function closeBrowser(): Promise<void> {
  await releaseAllParkedQuoteSessions();
  if (browser) {
    await browser.close().catch(() => undefined);
    browser = null;
  }
}

/** @deprecated 兼容 probe */
export async function newCheckedPage(reloginAttempt = false): Promise<Page> {
  const { page } = await openQuotePage(quotePageAdapter, reloginAttempt);
  return page;
}

export function assertSessionEnv(): void {
  assertRpaSelectorsEnv();
  if (process.env.RPA_MOCK_MODE === "true") {
    return;
  }
  void getPrimaryMothershipQuoteUrl();
}
