import { existsSync, readFileSync, readdirSync } from "node:fs";
import { join } from "node:path";
import type { AddressLookupInput } from "@/modules/address/types";
import type { ManualInteractionRecord } from "@/workers/rpa/selection-trace";

export type GoldStandardClickTarget = {
  textPreview: string;
  className: string;
  tagName: string;
  dataOptionId: string | null;
  side: "pickup" | "delivery";
  sourceDir: string;
};

type GoldFile = {
  pickup?: { selectionClicks: ManualInteractionRecord[] };
  delivery?: { selectionClicks: ManualInteractionRecord[] };
};

const GOLD_ROOT = join(process.cwd(), ".rpa", "address-event-compare");

function normalizeText(text: string): string {
  return text.replace(/\s+/g, " ").trim().toLowerCase();
}

function stripCountrySuffix(label: string): string {
  return label.replace(/,\s*USA\s*$/i, "").trim();
}

/** 金样本 textPreview 与目标 description 的匹配分（越高越优先） */
export function scoreGoldTextMatch(
  description: string,
  query: AddressLookupInput,
  textPreview: string,
): number {
  const desc = normalizeText(description);
  const preview = normalizeText(textPreview);
  if (!desc || !preview) {
    return 0;
  }
  if (desc === preview) {
    return 100;
  }
  if (preview.includes(desc) || desc.includes(preview)) {
    return 90;
  }
  const descNoCountry = normalizeText(stripCountrySuffix(description));
  const previewNoCountry = normalizeText(stripCountrySuffix(textPreview));
  if (descNoCountry === previewNoCountry) {
    return 85;
  }
  if (
    previewNoCountry.includes(descNoCountry) ||
    descNoCountry.includes(previewNoCountry)
  ) {
    return 75;
  }
  const street = normalizeText(query.street);
  const city = normalizeText(query.city);
  let score = 0;
  if (street && preview.includes(street)) {
    score += 40;
  }
  if (city && preview.includes(city)) {
    score += 30;
  }
  const state = normalizeText(query.state);
  if (state) {
    if (state.length === 2) {
      const stateRe = new RegExp(
        `(,|\\b)${state.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(\\b|,|$)`,
      );
      if (stateRe.test(preview)) {
        score += 20;
      }
    } else if (preview.includes(state)) {
      score += 20;
    }
  }
  const streetHead = street.split(",")[0]?.trim() ?? "";
  if (score < 75 && streetHead.length >= 8 && !preview.includes(streetHead)) {
    return 0;
  }
  const streetNum = query.street.match(/^\d+/)?.[0];
  if (score < 75 && streetNum && !preview.includes(streetNum.toLowerCase())) {
    return 0;
  }
  return score;
}

function toTarget(
  click: ManualInteractionRecord,
  side: "pickup" | "delivery",
  sourceDir: string,
): GoldStandardClickTarget {
  return {
    textPreview: click.target.textPreview,
    className: click.target.className,
    tagName: click.target.tagName,
    dataOptionId: click.target.dataOptionId,
    side,
    sourceDir,
  };
}

function loadGoldTargetsFromDir(dir: string): GoldStandardClickTarget[] {
  const path = join(dir, "manual-interactions-gold.json");
  if (!existsSync(path)) {
    return [];
  }
  let data: GoldFile;
  try {
    data = JSON.parse(readFileSync(path, "utf8")) as GoldFile;
  } catch {
    return [];
  }
  const out: GoldStandardClickTarget[] = [];
  for (const click of data.pickup?.selectionClicks ?? []) {
    out.push(toTarget(click, "pickup", dir));
  }
  for (const click of data.delivery?.selectionClicks ?? []) {
    out.push(toTarget(click, "delivery", dir));
  }
  return out;
}

/** 扫描 .rpa/address-event-compare 下全部金样本点击目标 */
export function loadAllGoldStandardTargets(): GoldStandardClickTarget[] {
  if (!existsSync(GOLD_ROOT)) {
    return [];
  }
  const targets: GoldStandardClickTarget[] = [];
  for (const name of readdirSync(GOLD_ROOT, { withFileTypes: true })) {
    if (!name.isDirectory()) {
      continue;
    }
    targets.push(...loadGoldTargetsFromDir(join(GOLD_ROOT, name.name)));
  }
  return targets;
}

/**
 * 按 description/query 匹配最相关的金样本点击目标（同侧优先）。
 * 用于运行时复现人工点选 DOM 特征。
 */
export function findGoldStandardTargets(
  description: string,
  query: AddressLookupInput,
  side: "pickup" | "delivery",
  minScore = 50,
): GoldStandardClickTarget[] {
  const all = loadAllGoldStandardTargets();
  const scored = all
    .map((target) => ({
      target,
      score:
        scoreGoldTextMatch(description, query, target.textPreview) +
        (target.side === side ? 5 : 0),
    }))
    .filter((item) => item.score >= minScore)
    .sort((a, b) => b.score - a.score);

  const seen = new Set<string>();
  const unique: GoldStandardClickTarget[] = [];
  for (const { target } of scored) {
    const key = `${target.textPreview}|${target.className}`;
    if (seen.has(key)) {
      continue;
    }
    seen.add(key);
    unique.push(target);
  }
  return unique.slice(0, 5);
}
