import type { Page } from "playwright";
import type { CargoCommitProbe } from "@/workers/rpa/cargo-lock";

/** MotherShip 重量输入框与 API freight.weightLbs 均为单托 lb */
export const CARGO_WEIGHT_TOLERANCE_LB = 1.5;
export const CARGO_WEIGHT_TOLERANCE_KG = 0.5;

const LB_TO_KG = 2.20462;

export type MotherShipWeightDisplay = {
  displayValue: string;
  unit: "lb" | "kg";
  weightLbPerPallet: number;
};

export type ExpectedCargoWeight = MotherShipWeightDisplay & {
  palletCount: number;
};

export type LiveWeightFieldMeta = {
  placeholder: string;
  ariaLabel: string;
  adjacentText: string;
  unit: "lb" | "kg";
};

/** 仅从单个字段的 placeholder/label/相邻文案推断单位（禁止合并多 spec 字符串） */
export function inferWeightUnitFromFieldHint(hint: string): "lb" | "kg" {
  const text = hint.trim();
  if (!text) {
    return "lb";
  }
  const hasKg = /(?:\bkg\b|公斤|千克)/i.test(text);
  const hasLb = /(?:\blbs?\b|磅)/i.test(text);
  if (hasKg && !hasLb) {
    return "kg";
  }
  if (hasLb) {
    return "lb";
  }
  return "lb";
}

/** 按页面实际单位生成填入值（API 入参始终为单托 lb） */
export function buildWeightDisplayForUnit(
  weightLbPerPallet: number,
  unit: "lb" | "kg",
): MotherShipWeightDisplay {
  if (unit === "kg") {
    const kg = Math.round((weightLbPerPallet / LB_TO_KG) * 100) / 100;
    return {
      displayValue: String(kg),
      unit: "kg",
      weightLbPerPallet,
    };
  }
  return {
    displayValue: String(weightLbPerPallet),
    unit: "lb",
    weightLbPerPallet,
  };
}

/**
 * @deprecated 仅单测/回退：必须传入**单个**可见字段 hint，不得传 env 全量 specs
 */
export function resolveMotherShipWeightDisplay(
  weightLbPerPallet: number,
  singleFieldHint: string,
): MotherShipWeightDisplay {
  const unit = inferWeightUnitFromFieldHint(singleFieldHint);
  return buildWeightDisplayForUnit(weightLbPerPallet, unit);
}

/** 读取 widget 内当前可见、可编辑的重量输入框单位指示 */
export async function readLiveWeightFieldMeta(
  page: Page,
  widgetSelector: string,
): Promise<LiveWeightFieldMeta | null> {
  return page.evaluate((sel) => {
    const widget = document.querySelector(sel);
    if (!widget) {
      return null;
    }

    const inputs = widget.querySelectorAll<HTMLInputElement>("input");
    for (const inp of inputs) {
      const visible = inp.offsetParent !== null;
      const editable =
        visible &&
        !inp.disabled &&
        inp.readOnly === false &&
        inp.getAttribute("aria-readonly") !== "true";
      if (!editable) {
        continue;
      }

      const placeholder = inp.placeholder ?? "";
      const ariaLabel = inp.getAttribute("aria-label") ?? "";
      const id = inp.id;
      let adjacentText = "";
      if (id) {
        const label = widget.querySelector(`label[for="${id}"]`);
        adjacentText = label?.textContent?.trim() ?? "";
      }
      const hint = `${placeholder} ${ariaLabel} ${adjacentText}`;
      if (!/weight|重量|lbs|lb|kg|公斤|千克|磅/i.test(hint)) {
        continue;
      }

      const hasKg = /(?:\bkg\b|公斤|千克)/i.test(hint);
      const hasLb = /(?:\blbs?\b|磅)/i.test(hint);
      let unit: "lb" | "kg" = "lb";
      if (hasKg && !hasLb) {
        unit = "kg";
      }

      return {
        placeholder,
        ariaLabel,
        adjacentText,
        unit,
      };
    }
    return null;
  }, widgetSelector);
}

/** 按 MotherShip 页面当前重量字段实际单位决定填入值（轮询至字段可见） */
export async function resolveMotherShipWeightDisplayFromPage(
  page: Page,
  widgetSelector: string,
  weightLbPerPallet: number,
  waitMs = 12_000,
): Promise<MotherShipWeightDisplay> {
  const deadline = Date.now() + waitMs;
  while (Date.now() < deadline) {
    const live = await readLiveWeightFieldMeta(page, widgetSelector);
    if (live) {
      return buildWeightDisplayForUnit(weightLbPerPallet, live.unit);
    }
    await page.waitForTimeout(150);
  }
  return buildWeightDisplayForUnit(weightLbPerPallet, "lb");
}

function parseSummaryWeightLb(text: string): number | null {
  const patterns = [
    /x\s*(\d{2,5})\s*Lbs/i,
    /(\d{2,5})Lbs/i,
    /\b(\d{2,5})\s*(?:lbs?|kg|公斤)\b/i,
  ];
  for (const re of patterns) {
    const m = text.match(re);
    if (m) {
      const n = Number(m[1]);
      if (Number.isFinite(n) && n > 0) {
        return n;
      }
    }
  }
  return null;
}

function summaryWeightMatchesExpected(
  summaryWeight: number,
  expected: ExpectedCargoWeight,
): boolean {
  const perPalletOk =
    Math.abs(summaryWeight - expected.weightLbPerPallet) <=
    CARGO_WEIGHT_TOLERANCE_LB;
  const totalExpected = expected.weightLbPerPallet * expected.palletCount;
  const totalOk =
    Math.abs(summaryWeight - totalExpected) <=
    CARGO_WEIGHT_TOLERANCE_LB * expected.palletCount;
  if (expected.unit === "kg") {
    const kg = Number(expected.displayValue);
    return (
      Math.abs(summaryWeight - kg) <= CARGO_WEIGHT_TOLERANCE_KG ||
      Math.abs(summaryWeight - kg * expected.palletCount) <=
        CARGO_WEIGHT_TOLERANCE_KG * expected.palletCount
    );
  }
  return perPalletOk || totalOk;
}

/** widget 内重量/托盘是否与请求一致（单托语义） */
export function probeWeightMatchesExpected(
  probe: CargoCommitProbe,
  expected: ExpectedCargoWeight,
): boolean {
  if (
    probe.internalPalletCount !== null &&
    probe.internalPalletCount !== expected.palletCount
  ) {
    return false;
  }

  if (probe.internalWeight !== null && probe.internalWeight > 0) {
    if (expected.unit === "kg") {
      return (
        Math.abs(probe.internalWeight - Number(expected.displayValue)) <=
        CARGO_WEIGHT_TOLERANCE_KG
      );
    }
    return (
      Math.abs(probe.internalWeight - expected.weightLbPerPallet) <=
      CARGO_WEIGHT_TOLERANCE_LB
    );
  }

  const summaryWeight = parseSummaryWeightLb(probe.widgetTextPreview);
  if (summaryWeight === null) {
    return false;
  }
  return summaryWeightMatchesExpected(summaryWeight, expected);
}

/** session / storageState 残留货物摘要且与本次请求不一致 */
export function isStaleCargoState(
  probe: CargoCommitProbe,
  expected: ExpectedCargoWeight,
): boolean {
  if (!probe.hasSummaryChip) {
    return false;
  }
  return !probeWeightMatchesExpected(probe, expected);
}
