import type { Page } from "playwright";
import {
  clickFirstVisibleFromSpecs,
  getSelectorSpecs,
} from "@/lib/rpa/selector-specs";
import { pageLocator } from "@/lib/rpa/locator";
import { RpaError } from "@/modules/rpa/errors";
import {
  expandCargoEditor,
  isCargoFieldsVisible,
  reopenInlineCargoStep,
  waitForCargoEditorOpen,
} from "@/workers/rpa/cargo-editor";
import {
  probeCargoCommitState,
  type ExpectedCargoCommit,
} from "@/workers/rpa/cargo-lock";
import {
  probeWeightMatchesExpected,
  type ExpectedCargoWeight,
} from "@/workers/rpa/cargo-weight";

const POLL_MS = 250;
const MAX_REMOVE_ROUNDS = 12;

const FREIGHT_SUMMARY_RE =
  /\d+\s*(?:pallet|托盘)s?|\d+W,\s*x\s*\d+L|(\d{2,5})Lbs|\b\d{2,5}\s*(?:lbs?|kg|公斤)\b/i;

const REMOVE_BUTTON_NAME_RE =
  /remove|delete|clear|trash|删除|移除|清除/i;

const ADD_FREIGHT_NAME_RE =
  /ADD ITEM|Add item|Add freight|Add Freight|添加货物|添加货品|新增/i;

function hasFreightSummary(text: string): boolean {
  return FREIGHT_SUMMARY_RE.test(text);
}

/** 摘要是否仍含货物行（用于判断删除是否完成） */
export function widgetHasFreightSummary(widgetTextPreview: string): boolean {
  return hasFreightSummary(widgetTextPreview);
}

async function clickFirstRemoveInWidget(
  page: Page,
  widgetSelector: string,
): Promise<boolean> {
  const fromEnv = await clickFirstVisibleFromSpecs(
    page,
    getSelectorSpecs("RPA_SELECTOR_FREIGHT_REMOVE"),
  );
  if (fromEnv) {
    await page.waitForTimeout(POLL_MS);
    return true;
  }

  const widget = pageLocator(page, widgetSelector);
  const scoped = [
    widget.locator('button[aria-label*="remove" i]').first(),
    widget.locator('button[aria-label*="delete" i]').first(),
    widget.locator('button[aria-label*="Remove" i]').first(),
    widget.locator('button[aria-label*="Delete" i]').first(),
    widget.getByRole("button", { name: REMOVE_BUTTON_NAME_RE }).first(),
  ];

  for (const loc of scoped) {
    if (!(await loc.isVisible().catch(() => false))) {
      continue;
    }
    await loc.click({ timeout: 5_000, force: true }).catch(() => undefined);
    await page.waitForTimeout(POLL_MS);
    return true;
  }

  const clicked = await page.evaluate((sel) => {
    const root = document.querySelector(sel);
    if (!root) {
      return false;
    }
    const buttons = root.querySelectorAll<HTMLButtonElement>("button");
    for (const btn of buttons) {
      const label = (
        btn.getAttribute("aria-label") ??
        btn.innerText ??
        btn.title ??
        ""
      ).trim();
      if (!/remove|delete|trash|删除|移除/i.test(label)) {
        continue;
      }
      if (btn.offsetParent === null || btn.disabled) {
        continue;
      }
      btn.click();
      return true;
    }
    return false;
  }, widgetSelector);

  if (clicked) {
    await page.waitForTimeout(POLL_MS);
  }
  return clicked;
}

/**
 * 删除 widget 内所有已存在货物行（展开 editor 后逐条点 Remove）。
 * @returns 点击删除次数
 */
export async function removeAllFreightRows(
  page: Page,
  widgetSelector: string,
): Promise<number> {
  let removed = 0;

  for (let round = 0; round < MAX_REMOVE_ROUNDS; round += 1) {
    const probe = await probeCargoCommitState(page, widgetSelector);
    if (!hasFreightSummary(probe.widgetTextPreview)) {
      console.log(`[rpa] cargo-reset: 无残留货物摘要（removed=${removed}）`);
      return removed;
    }

    if (!(await isCargoFieldsVisible(page, widgetSelector))) {
      await expandCargoEditor(page, widgetSelector).catch(() => undefined);
      await reopenInlineCargoStep(page, widgetSelector).catch(() => undefined);
    }

    const clicked = await clickFirstRemoveInWidget(page, widgetSelector);
    if (!clicked) {
      const widget = pageLocator(page, widgetSelector);
      const summary = widget
        .getByText(/\d+W,\s*x\s*\d+L|\d{2,5}Lbs|\d+\s*(?:pallet|托盘)s?/i)
        .first();
      if (await summary.isVisible().catch(() => false)) {
        await summary.click({ timeout: 3_000, force: true }).catch(() => undefined);
        await page.waitForTimeout(POLL_MS);
        if (await clickFirstRemoveInWidget(page, widgetSelector)) {
          removed += 1;
          continue;
        }
      }
      break;
    }
    removed += 1;
  }

  const after = await probeCargoCommitState(page, widgetSelector);
  if (hasFreightSummary(after.widgetTextPreview)) {
    throw new RpaError(
      "CARGO_RESET_FAILED",
      `无法删除 MotherShip 残留货物行（preview=${after.widgetTextPreview.slice(0, 120)}）`,
      { retryable: true },
    );
  }

  console.log(`[rpa] cargo-reset: 已删除 ${removed} 条货物行`);
  return removed;
}

async function widgetHasEditableWeightField(
  page: Page,
  widgetSelector: string,
): Promise<boolean> {
  return page.evaluate((sel) => {
    const widget = document.querySelector(sel);
    if (!widget) {
      return false;
    }
    for (const inp of widget.querySelectorAll<HTMLInputElement>("input")) {
      if (inp.offsetParent === null || inp.disabled) {
        continue;
      }
      const ph = inp.placeholder ?? "";
      if (/weight|重量|lbs|lb|kg|公斤|磅/i.test(ph)) {
        return true;
      }
    }
    return false;
  }, widgetSelector);
}

/** 点击 ADD ITEM / Add Freight，进入空白货物编辑态 */
export async function clickAddFreightItem(
  page: Page,
  widgetSelector: string,
): Promise<void> {
  const fromEnv = await clickFirstVisibleFromSpecs(
    page,
    getSelectorSpecs("RPA_SELECTOR_FREIGHT_ADD"),
  );
  if (fromEnv) {
    await page.waitForTimeout(POLL_MS);
    return;
  }

  const widget = pageLocator(page, widgetSelector);
  const triggers = [
    widget.getByRole("button", { name: ADD_FREIGHT_NAME_RE }).first(),
    page.getByRole("button", { name: /^ADD ITEM$/i }).first(),
    page.getByText(/^ADD ITEM$/i).first(),
  ];

  for (const loc of triggers) {
    if (!(await loc.isVisible().catch(() => false))) {
      continue;
    }
    await loc.click({ timeout: 8_000, force: true });
    await page.waitForTimeout(POLL_MS);
    console.log("[rpa] cargo-reset: 已点击 Add Freight / ADD ITEM");
    return;
  }

  if (
    (await isCargoFieldsVisible(page, widgetSelector)) &&
    (await widgetHasEditableWeightField(page, widgetSelector))
  ) {
    return;
  }

  await expandCargoEditor(page, widgetSelector);
  await waitForCargoEditorOpen(page, widgetSelector);
}

/** 提交前断言：widget 摘要托盘数/重量与请求一致，不符立即 fail-fast */
export async function assertWidgetCargoSummary(
  page: Page,
  widgetSelector: string,
  expected: ExpectedCargoCommit,
): Promise<void> {
  const probe = await probeCargoCommitState(page, widgetSelector);

  if (
    expected.palletCount !== undefined &&
    probe.internalPalletCount !== null &&
    probe.internalPalletCount !== expected.palletCount
  ) {
    throw new RpaError(
      "CARGO_WEIGHT_MISMATCH",
      `货物托盘数与请求不一致（widget=${probe.internalPalletCount} expected=${expected.palletCount}）`,
      { retryable: true },
    );
  }

  if (expected.weight && !probeWeightMatchesExpected(probe, expected.weight)) {
    throw new RpaError(
      "CARGO_WEIGHT_MISMATCH",
      `货物重量与请求不一致（widget=${probe.internalWeight ?? probe.widgetTextPreview.slice(0, 80)} expected=${expected.weight.weightLbPerPallet}lb/托 × ${expected.weight.palletCount}托）`,
      { retryable: true },
    );
  }
}

export type { ExpectedCargoWeight };
