import {
  normalizeCountryKey,
  SUPPORTED_COUNTRY_KEYS,
} from "./location-support.js";

const supportedCountryKeySet = new Set(SUPPORTED_COUNTRY_KEYS);

const LOCATION_ALIASES: Record<string, string> = {
  uk: "united kingdom",
  us: "united states",
  usa: "united states",
};

export function normalizeLocationToken(
  value: string | null | undefined,
): string {
  const normalized = value?.trim().toLowerCase().replace(/\s+/g, " ") ?? "";
  if (!normalized) return "";
  return LOCATION_ALIASES[normalized] ?? normalized;
}

/**
 * If search geography includes a supported country token (e.g. "UK", "Canada"),
 * returns its normalized country key; otherwise null (e.g. "London" only).
 */
export function inferCountryKeyFromSearchGeography(
  searchCities?: string | null,
  jobspyLocation?: string | null,
): string | null {
  const raw = searchCities?.trim() || jobspyLocation?.trim();
  if (!raw) return null;
  for (const token of parseSearchCitiesSetting(raw)) {
    const key = normalizeCountryKey(token);
    if (supportedCountryKeySet.has(key)) return key;
  }
  return null;
}

/**
 * Parses a job listing location string and returns normalized country keys
 * (e.g. "London, UK" → ["united kingdom"]). Empty when no supported country tokens.
 */
export function inferCountryKeysFromJobLocation(
  location: string | null | undefined,
): string[] {
  if (!location?.trim()) return [];
  const keys = new Set<string>();
  for (const segment of location.split(/[,;|]/)) {
    const trimmed = segment.trim();
    if (!trimmed) continue;
    const key = normalizeCountryKey(trimmed);
    if (supportedCountryKeySet.has(key)) keys.add(key);
  }
  const whole = normalizeCountryKey(location);
  if (supportedCountryKeySet.has(whole)) keys.add(whole);
  return [...keys];
}

export function parseSearchCitiesSetting(
  value: string | null | undefined,
): string[] {
  const trimmed = value?.trim();
  if (!trimmed) return [];
  const split = trimmed.includes("|")
    ? trimmed.split("|")
    : trimmed.includes("\n")
      ? trimmed.split("\n")
      : [trimmed];
  const seen = new Set<string>();
  const out: string[] = [];
  for (const raw of split) {
    const normalized = raw.trim();
    if (!normalized) continue;
    const key = normalized.toLowerCase();
    if (seen.has(key)) continue;
    seen.add(key);
    out.push(normalized);
  }
  return out;
}

interface ResolveSearchCitiesOptions {
  list?: string[] | null;
  single?: string | null;
  env?: string | null;
  fallback?: string | null;
}

export function resolveSearchCities(
  options: ResolveSearchCitiesOptions,
): string[] {
  // Priority order:
  // 1) explicit list (searchCities array in config)
  // 2) explicit single value
  // 3) environment fallback
  // 4) final hardcoded/default fallback
  if (options.list && options.list.length > 0) {
    const parsedList = parseSearchCitiesSetting(options.list.join("|"));
    if (parsedList.length > 0) return parsedList;
  }

  const fallbackCandidates = [options.single, options.env, options.fallback];
  for (const candidate of fallbackCandidates) {
    if (candidate === null || candidate === undefined) continue;
    const parsed = parseSearchCitiesSetting(candidate);
    if (parsed.length > 0) return parsed;
  }

  return [];
}

export function serializeSearchCitiesSetting(cities: string[]): string | null {
  if (cities.length === 0) return null;
  return cities.join("|");
}

export function shouldApplyStrictCityFilter(
  city: string,
  country: string,
): boolean {
  const normalizedCity = normalizeLocationToken(city);
  const normalizedCountry = normalizeCountryKey(country);
  if (!normalizedCity || !normalizedCountry) return false;
  return normalizedCity !== normalizedCountry;
}

export function matchesRequestedCity(
  jobLocation: string | undefined,
  requestedCity: string,
): boolean {
  const normalizedJobLocation = normalizeLocationToken(jobLocation)
    .replace(/[^a-z0-9]+/g, " ")
    .trim();
  const normalizedRequestedLocation = normalizeLocationToken(requestedCity)
    .replace(/[^a-z0-9]+/g, " ")
    .trim();
  if (!normalizedJobLocation || !normalizedRequestedLocation) return false;

  const jobTokens = normalizedJobLocation.split(" ");
  const requestedTokens = normalizedRequestedLocation.split(" ");
  if (requestedTokens.length > jobTokens.length) return false;

  for (let i = 0; i <= jobTokens.length - requestedTokens.length; i += 1) {
    let matches = true;
    for (let j = 0; j < requestedTokens.length; j += 1) {
      if (jobTokens[i + j] !== requestedTokens[j]) {
        matches = false;
        break;
      }
    }
    if (matches) return true;
  }

  return false;
}
