import type { Channel } from "@/types/xtream";

/**
 * Build a stable sort comparator that bumps channels matching the user's
 * detected country (by name/category prefix) to the top of the list,
 * while preserving the original order otherwise.
 *
 * Heuristics — IPTV playlists are wildly inconsistent, so we match
 * against:
 *  - The 2-letter ISO country code as a token at the start of the name
 *    or category (e.g. "FR |", "MA -", "US:", "[DE]"…).
 *  - The full English country name as a substring (case-insensitive).
 *  - A few common alias/native names (e.g. "Maroc" for Morocco,
 *    "Deutschland" for Germany, etc.) so the heuristic stays useful
 *    on Arabic / French / German playlists.
 *
 * Returns (a, b) => number suitable for Array.prototype.sort.
 */
const ALIASES: Record<string, string[]> = {
  US: ["united states", "usa"],
  GB: ["united kingdom", "uk", "britain"],
  FR: ["france"],
  DE: ["germany", "deutschland"],
  ES: ["spain", "españa", "espana"],
  IT: ["italy", "italia"],
  RO: ["romania", "românia"],
  RU: ["russia", "россия"],
  AE: ["united arab emirates", "uae", "الإمارات"],
  SA: ["saudi arabia", "arabie saoudite", "السعودية"],
  MA: ["morocco", "maroc", "المغرب"],
  DZ: ["algeria", "algérie", "الجزائر"],
  TN: ["tunisia", "tunisie", "تونس"],
  EG: ["egypt", "égypte", "مصر"],
  TR: ["turkey", "turquie", "türkiye"],
  KR: ["korea", "south korea"],
  PT: ["portugal"],
  PH: ["philippines", "pilipinas"],
};

const buildTokens = (countryCode?: string, countryName?: string): string[] => {
  if (!countryCode && !countryName) return [];
  const cc = (countryCode || "").toUpperCase();
  const tokens: string[] = [];
  if (cc) {
    tokens.push(cc);
    const aliases = ALIASES[cc];
    if (aliases) tokens.push(...aliases);
  }
  if (countryName) tokens.push(countryName.toLowerCase());
  return Array.from(new Set(tokens.map((t) => t.trim()).filter(Boolean)));
};

const ccBoundaryRegex = (cc: string) =>
  // Country-code as a standalone token at the start of a string. Matches
  //   "FR |", "FR-", "FR:", "[FR]", "(FR)", "FR " etc.
  new RegExp(`(^|[^A-Z])${cc}([^A-Z]|$)`, "i");

export const channelMatchesCountry = (
  ch: Pick<Channel, "name" | "category">,
  countryCode?: string,
  countryName?: string,
): boolean => {
  const tokens = buildTokens(countryCode, countryName);
  if (tokens.length === 0) return false;
  const haystack = `${ch.name || ""} | ${ch.category || ""}`.toLowerCase();
  for (const tok of tokens) {
    if (tok.length === 2) {
      if (ccBoundaryRegex(tok).test(haystack)) return true;
    } else {
      if (haystack.includes(tok)) return true;
    }
  }
  return false;
};

/** Stable geo-prioritised sort: matches first, original order preserved. */
export const sortChannelsByGeo = (
  channels: Channel[],
  countryCode?: string,
  countryName?: string,
): Channel[] => {
  if (!channels?.length) return channels;
  if (!countryCode && !countryName) return channels;
  const matches: Channel[] = [];
  const rest: Channel[] = [];
  for (const ch of channels) {
    if (channelMatchesCountry(ch, countryCode, countryName)) matches.push(ch);
    else rest.push(ch);
  }
  if (matches.length === 0) return channels;
  return [...matches, ...rest];
};

/** Same idea but for categories — we just bump categories whose name
 *  contains the country/code so users see "France HD" before "Latino". */
export const sortCategoriesByGeo = (
  categories: string[],
  countryCode?: string,
  countryName?: string,
): string[] => {
  if (!categories?.length) return categories;
  const tokens = buildTokens(countryCode, countryName);
  if (tokens.length === 0) return categories;
  const matches: string[] = [];
  const rest: string[] = [];
  for (const c of categories) {
    if (c === "All") {
      rest.unshift(c); // keep "All" sentinel at the top
      continue;
    }
    const low = c.toLowerCase();
    let hit = false;
    for (const tok of tokens) {
      if (tok.length === 2) {
        if (ccBoundaryRegex(tok).test(low)) { hit = true; break; }
      } else if (low.includes(tok)) {
        hit = true;
        break;
      }
    }
    (hit ? matches : rest).push(c);
  }
  if (matches.length === 0) return categories;
  // "All" first, then matches, then the rest
  const allIdx = rest.indexOf("All");
  if (allIdx >= 0) rest.splice(allIdx, 1);
  return ["All", ...matches, ...rest];
};
