import { scoreSuggestionLabelMatch } from "@/workers/rpa/address-suggestions";
import { normalizeAxelPlaceId } from "@/workers/rpa/axel-selection-bridge";

export type AxelSearchCandidate = {
  placeId: string;
  description: string;
  mainText?: string;
  secondaryText?: string;
  types?: string[];
};

const STANDARD_PLACE_ID_RE = /^ChIJ[A-Za-z0-9_-]{23}$/;

function extractStreetNumber(query: string): string | null {
  return query.trim().match(/^\d+/)?.[0] ?? null;
}

function mainTextHasStreetNumber(
  streetNum: string,
  row: AxelSearchCandidate,
): boolean {
  const blob = `${row.mainText ?? ""} ${row.description}`.replace(/\s+/g, " ");
  return new RegExp(`\\b${streetNum}\\b`).test(blob);
}

function isRouteOnlyCandidate(row: AxelSearchCandidate): boolean {
  const types = row.types ?? [];
  return types.includes("route") && !types.includes("street_address");
}

function scoreCandidate(
  query: string,
  row: AxelSearchCandidate,
  streetNum: string | null,
): number {
  const label = row.description.trim();
  let score = scoreSuggestionLabelMatch(query, label);

  if (streetNum) {
    if (mainTextHasStreetNumber(streetNum, row)) {
      score += 80;
    } else {
      score -= 60;
    }
    if (isRouteOnlyCandidate(row)) {
      score -= 50;
    }
  }

  const normalized = normalizeAxelPlaceId(row.placeId);
  if (STANDARD_PLACE_ID_RE.test(normalized)) {
    score += 10;
  } else if (!row.placeId.startsWith("ChIJ")) {
    score -= 20;
  }

  return score;
}

/** 从 axel search 结果中选取与用户查询最匹配的候选 */
export function pickBestSearchCandidate(
  query: string,
  candidates: AxelSearchCandidate[],
): AxelSearchCandidate | null {
  if (candidates.length === 0) {
    return null;
  }

  const streetNum = extractStreetNumber(query);
  if (streetNum) {
    const withNumber = candidates.filter((row) =>
      mainTextHasStreetNumber(streetNum, row),
    );
    if (withNumber.length > 0) {
      return rankCandidates(query, withNumber, streetNum);
    }
  }

  return rankCandidates(query, candidates, streetNum);
}

function rankCandidates(
  query: string,
  candidates: AxelSearchCandidate[],
  streetNum: string | null,
): AxelSearchCandidate | null {
  const scored = candidates.map((row) => ({
    row,
    score: scoreCandidate(query, row, streetNum),
  }));
  scored.sort((a, b) => b.score - a.score);
  return scored[0]?.row ?? null;
}
