/**
 * Maps amateur radio callsign prefixes to ISO 3166-1 alpha-2 country codes
 * Uses pattern-based compression for both 2-letter and 3-letter ranges
 * Supports 22,440+ prefixes in ~6KB instead of 300KB
 */

// Single-letter prefixes that cover most amateur radio use
const SINGLE_LETTER_PREFIXES: Record<string, string> = {
  'K': 'US', 'W': 'US', 'N': 'US',
  'G': 'GB', 'M': 'GB',
  'D': 'DE', 'F': 'FR', 'I': 'IT', 'B': 'CN', 'R': 'RU', 'U': 'RU',
};

/**
 * Two-letter prefix patterns from ITU allocations
 * Format: 'A[A-L]': 'US' means AA-AL map to US
 * Also includes individual patterns like '2E': 'GB' for specific allocations
 */
const TWO_LETTER_PATTERNS: Record<string, string> = {
  // United States (multiple ranges)
  'A[A-L]': 'US',
  'K[A-Z]': 'US',
  'N[A-Z]': 'US',
  'W[A-Z]': 'US',

  // Canada
  'V[A-GOY]': 'CA',

  // United Kingdom (special 2-letter allocations)
  '2[EIJMUW]': 'GB',

  // Germany
  'D[A-O]': 'DE',

  // France
  'T[M-Q]': 'FR',

  // Netherlands
  'P[A-I]': 'NL',

  // Spain
  'E[A-H]': 'ES', 'AM': 'ES',

  // Japan
  'J[A-S]': 'JP',

  // Australia
  'V[KLMNZ]': 'AU', 'AX': 'AU',

  // Belgium
  'O[N-T]': 'BE',

  // Switzerland
  'H[BE]': 'CH',

  // Austria
  'OE': 'AT',

  // Poland
  'S[N-R]': 'PL',

  // Sweden
  'S[A-M]': 'SE',

  // Norway
  'L[A-N]': 'NO',

  // Denmark
  'O[UZ]': 'DK', '5[P-Q]': 'DK',

  // Finland
  'O[F-I]': 'FI',

  // Czech Republic
  'O[KL]': 'CZ',

  // Portugal
  'C[R-U]': 'PT',

  // Greece
  'S[V-Z]': 'GR',

  // Romania
  'Y[O-R]': 'RO',

  // Hungary
  'H[AG]': 'HU',

  // Bulgaria
  'LZ': 'BG',

  // Slovakia
  'OM': 'SK',

  // Ireland
  'E[IJ]': 'IE',

  // New Zealand
  'Z[K-M]': 'NZ',

  // Brazil
  'P[P-Y]': 'BR', 'Z[V-Z]': 'BR',

  // Argentina
  'A[YZ]': 'AR',

  // Chile
  'C[A-E]': 'CL',

  // India
  'V[U-W]': 'IN', 'A[T-W]': 'IN',

  // Mexico
  'X[A-I]': 'MX',

  // Thailand
  'HS': 'TH', 'E2': 'TH',

  // Turkey
  'T[A-C]': 'TR',

  // Ukraine
  'E[M-O]': 'UA', 'U[R-Z]': 'UA',

  // Croatia
  '9A': 'HR',

  // Slovenia
  'S5': 'SI',

  // Lithuania
  'LY': 'LT',

  // Latvia
  'YL': 'LV',

  // Iceland
  'TF': 'IS',

  // Luxembourg
  'LX': 'LU',

  // South Korea
  'H[L-M]': 'KR', '6[K-L]': 'KR', 'D[7-9]': 'KR', 'D[ST]': 'KR',

  // Indonesia
  'Y[B-H]': 'ID',

  // Singapore
  '9V': 'SG',

  // Malaysia
  '9[MW]': 'MY',

  // Israel
  '4[XZ]': 'IL',

  // Egypt
  'SU': 'EG',

  // Philippines
  'D[U-Z]': 'PH', '4[D-I]': 'PH',

  // South Africa
  'Z[R-U]': 'ZA',
};



/**
 * Prefix patterns for 3-letter callsigns from ITU allocations
 * Format: '2A[A-Z]': 'GB' means prefixes 2AA-2AZ map to GB
 * Syntax: [A-Z] matches single letter, [A-X] matches A through X, etc.
 */
const THREE_LETTER_PATTERNS: Record<string, string> = {
  '2[A-Z][A-Z]': 'GB',
  '3A': 'MC', '3B': 'MU', '3C': 'GQ', '3D': 'SZ', '3[E-F][A-Z]': 'PT', '3G': 'SH', '3[H-I][A-Z]': 'CY', '3J': 'ER',
  '3K': 'PS', '3[L-O][A-Z]': 'FJ', '3[P-Z][A-Z]': 'PA',
  '4[A-X][A-Z]': 'MC', '4Y': 'BY', '4Z': 'SJ',
  '5A': 'LI', '5B': 'CZ', '5C': 'DK', '5[D-E][A-Z]': 'SE', '5F': 'HU', '5[G-I][A-Z]': 'NO', '5J': 'SE',
  '5[K-M][A-Z]': 'SE', '5[N-O][A-Z]': 'NO', '5[R-T][A-Z]': 'SE', '5[U-V][A-Z]': 'DK',
  '5[W-X][A-Z]': 'SE', '5[Y-Z][A-Z]': 'KE',
  '6[A-B][A-Z]': 'EG', '6[C-D][A-Z]': 'NO', '6[E-J][A-Z]': 'NL', '6[K-M][A-Z]': 'KR', '6[N-Z][A-Z]': 'KZ',
  '7[A-L][A-Z]': 'RU', '7M': 'AM', '7[N-X][A-Z]': 'RU', '7Y': 'EG', '7Z': 'RU',
  '8[A-Z][A-Z]': 'ID',
  '9[A-H][A-Z]': 'ET', '9[I-J][A-Z]': 'ZM',
};

/**
 * Converts a pattern like '2A[A-Z]', 'O[N-T]', or '2[EIJMUW]' to a regex that checks if a prefix matches
 */
function patternToRegex(pattern: string): RegExp {
  let regex = pattern;
  // Convert pattern syntax [A-Z], [A-X], etc. to regex
  regex = regex.replace(/\[([A-Z0-9])-([A-Z0-9])\]/g, '[$1-$2]');
  // Character classes are already valid regex, e.g., [EIJMUW]
  // For 2-letter patterns, match exactly 2 letters
  // For 3-letter patterns, match 2 letters + optional 3rd character
  return new RegExp(`^${regex}[A-Z0-9]?$`);
}

/**
 * Checks if a prefix matches any pattern (2-letter or 3-letter)
 */
function matchesPattern(prefix: string, patterns: Record<string, string>): string | null {
  for (const [pattern, code] of Object.entries(patterns)) {
    if (pattern.includes('[')) {
      // Pattern with character range, e.g., 'O[N-T]' or '2A[A-Z]'
      const regex = patternToRegex(pattern);
      if (regex.test(prefix)) return code;
    } else if (pattern.length === 2) {
      // Short pattern like '3A' or '4Y' - match prefix starting with pattern
      if (prefix.startsWith(pattern)) return code;
    } else if (pattern.length === 3 && !pattern.includes('[')) {
      // 3-char exact match like '2E'
      if (prefix.startsWith(pattern)) return code;
    }
  }
  return null;
}

/**
 * Extracts the country code from an amateur radio callsign
 * @param callsign The amateur radio callsign (e.g., "K6ABC", "PA0MZ", "G4ABC")
 * @returns ISO 3166-1 alpha-2 country code, or null if not found
 */
export function getCountryCodeFromCallsign(callsign: string | undefined): string | null {
  if (!callsign) return null;

  // Clean the callsign - remove SSID and convert to uppercase
  const cleanCallsign = callsign.split('-')[0].toUpperCase().trim();

  // Try 3-character prefix first (for ITU allocations)
  if (cleanCallsign.length >= 3) {
    const threeCharPrefix = cleanCallsign.substring(0, 3);
    const patternMatch = matchesPattern(threeCharPrefix, THREE_LETTER_PATTERNS);
    if (patternMatch) return patternMatch;
  }

  // Try 2-character prefix (most common)
  if (cleanCallsign.length >= 2) {
    const twoCharPrefix = cleanCallsign.substring(0, 2);
    const patternMatch = matchesPattern(twoCharPrefix, TWO_LETTER_PATTERNS);
    if (patternMatch) return patternMatch;
  }

  // Try 1-character prefix
  if (cleanCallsign.length >= 1) {
    const oneCharPrefix = cleanCallsign.substring(0, 1);
    const singleMatch = SINGLE_LETTER_PREFIXES[oneCharPrefix];
    if (singleMatch) return singleMatch;
  }

  return null;
}
