// IARU band plans, by region.
//
// The band maps used to carry one hard-coded table — Region 1's — so a US or
// Australian operator saw 40 m stop at 7200 while stations sat spotted at 7250,
// and the SSB wash started 25 kHz early. The region is a station-level fact the
// operator states once (Settings → General); everything drawing a band edge or
// a mode segment reads it from here.
//
// The tables are deliberately coarse: a band map's wash is CONTEXT, not a
// regulatory chart. Only the segments that differ between regions in ways an
// operator notices are split out; national fine print (US licence classes,
// beacon slots) does not belong in a background tint.
import { writeUiPref } from '@/lib/uiPref';

export type IaruRegion = 1 | 2 | 3;
export const KEY_IARU_REGION = 'opslog.iaruRegion';

export function iaruRegion(): IaruRegion {
  try {
    const v = localStorage.getItem(KEY_IARU_REGION);
    return v === '2' ? 2 : v === '3' ? 3 : 1;
  } catch { return 1; }
}

export function setIaruRegion(r: IaruRegion): void {
  writeUiPref(KEY_IARU_REGION, String(r));
  listeners.forEach((l) => l());
}

// The band maps capture the plan inside their render, so a change must reach
// them the way the distance unit reaches the grids.
const listeners = new Set<() => void>();
export function subscribeIaruRegion(fn: () => void): () => void {
  listeners.add(fn);
  return () => { listeners.delete(fn); };
}

export type SegMode = 'cw' | 'digi' | 'phone';
type Seg = [number, number, SegMode];

interface Plan {
  ranges: Record<string, [number, number]>;
  segments: Record<string, Seg[]>;
}

// Region 1 — Europe / Africa / Middle East / northern Asia. The baseline the
// other two override.
const R1: Plan = {
  ranges: {
    '160m': [1800, 2000], '80m': [3500, 3800], '60m': [5350, 5450],
    '40m': [7000, 7200], '30m': [10100, 10150], '20m': [14000, 14350],
    '17m': [18068, 18168], '15m': [21000, 21450], '12m': [24890, 24990],
    '10m': [28000, 29700], '6m': [50000, 50500], '4m': [70000, 70500],
    '2m': [144000, 146000], '70cm': [430000, 440000],
  },
  segments: {
    '160m': [[1800, 1838, 'cw'], [1838, 1840, 'digi'], [1840, 2000, 'phone']],
    '80m': [[3500, 3580, 'cw'], [3580, 3600, 'digi'], [3600, 3800, 'phone']],
    '60m': [[5350, 5450, 'phone']],
    '40m': [[7000, 7040, 'cw'], [7040, 7100, 'digi'], [7100, 7200, 'phone']],
    '30m': [[10100, 10130, 'cw'], [10130, 10150, 'digi']],
    '20m': [[14000, 14070, 'cw'], [14070, 14100, 'digi'], [14100, 14350, 'phone']],
    '17m': [[18068, 18095, 'cw'], [18095, 18110, 'digi'], [18110, 18168, 'phone']],
    '15m': [[21000, 21070, 'cw'], [21070, 21150, 'digi'], [21150, 21450, 'phone']],
    '12m': [[24890, 24915, 'cw'], [24915, 24940, 'digi'], [24940, 24990, 'phone']],
    '10m': [[28000, 28070, 'cw'], [28070, 28300, 'digi'], [28300, 29700, 'phone']],
    '6m': [[50000, 50100, 'cw'], [50100, 50500, 'phone']],
  },
};

// Region 2 — the Americas. 80 m runs to 4000 and 40 m to 7300, with phone from
// 7125 (the whole point of asking the region: a KP4 ragchew on 7250 must not
// hang past the top of the map).
const R2: Plan = {
  ranges: {
    ...R1.ranges,
    '80m': [3500, 4000], '40m': [7000, 7300],
    '6m': [50000, 54000], '2m': [144000, 148000], '70cm': [420000, 450000],
  },
  segments: {
    ...R1.segments,
    '80m': [[3500, 3570, 'cw'], [3570, 3600, 'digi'], [3600, 4000, 'phone']],
    '40m': [[7000, 7040, 'cw'], [7040, 7125, 'digi'], [7125, 7300, 'phone']],
    '6m': [[50000, 50100, 'cw'], [50100, 54000, 'phone']],
  },
};

// Region 3 — Asia-Pacific. 80 m to 3900; 40 m as Region 1's shape.
const R3: Plan = {
  ranges: {
    ...R1.ranges,
    '80m': [3500, 3900],
    '6m': [50000, 54000], '2m': [144000, 148000], '70cm': [430000, 450000],
  },
  segments: {
    ...R1.segments,
    '80m': [[3500, 3535, 'cw'], [3535, 3600, 'digi'], [3600, 3900, 'phone']],
    '6m': [[50000, 50100, 'cw'], [50100, 54000, 'phone']],
  },
};

function plan(): Plan {
  const r = iaruRegion();
  return r === 2 ? R2 : r === 3 ? R3 : R1;
}

export function bandRange(band: string): [number, number] | undefined {
  return plan().ranges[band];
}

export function bandSegments(band: string): Seg[] {
  return plan().segments[band] ?? [];
}

// bandForMHz maps a dial frequency (MHz) to its ADIF band, or '' when it falls
// outside every known allocation.
//
// Lives here rather than in a panel because more than one place has to answer
// the same question the same way: the entry form retunes on a typed frequency,
// and the QSO editor has to keep band and frequency agreeing when one of them
// is corrected. Kept in step with BandFromHz on the Go side.
export function bandForMHz(mhz: number): string {
  if (!mhz || isNaN(mhz)) return '';
  const plan: [number, number, string][] = [
    [1.8, 2.0, '160m'], [3.5, 4.0, '80m'], [5.06, 5.45, '60m'], [7.0, 7.3, '40m'],
    [10.1, 10.15, '30m'], [14.0, 14.35, '20m'], [18.068, 18.168, '17m'], [21.0, 21.45, '15m'],
    [24.89, 24.99, '12m'], [28.0, 29.7, '10m'], [50, 54, '6m'], [70, 71, '4m'],
    [144, 148, '2m'], [222, 225, '1.25m'], [420, 450, '70cm'], [902, 928, '33cm'], [1240, 1300, '23cm'],
    // Microwave, ADIF 3.1.7 ranges.
    [2300, 2450, '13cm'], [3300, 3500, '9cm'], [5650, 5925, '6cm'], [10000, 10500, '3cm'],
    [24000, 24250, '1.25cm'], [47000, 47200, '6mm'], [75500, 81000, '4mm'],
    [119980, 123000, '2.5mm'], [134000, 149000, '2mm'], [241000, 250000, '1mm'],
  ];
  for (const [lo, hi, b] of plan) if (mhz >= lo && mhz <= hi) return b;
  return '';
}
