import xlsx from 'xlsx';
import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// Edades exactas disponibles (incluye rangos infantiles 0-4 y 5-14 para AXA)
const EDAD_BRACKETS = [0, 5, 18, 20, 22, 25, 28, 30, 32, 35, 38, 40, 42, 45, 48, 50, 52, 55, 58, 60, 62, 65, 70, 80];

// Key: `${planId}_${edadBracket}` → factor (género no afecta el factor)
const factorMap = new Map<string, number>();

// Key: planId → set of available departments
const deptsByPlan = new Map<number, Set<string>>();

// Key: planId → set of available EPS
const epsByPlan = new Map<number, Set<string>>();

// Departamentos y EPS conocidos en la DB (para detectar valores fuera del catálogo)
const knownDepts = new Set<string>();
const knownEps   = new Set<string>();

// AXA Colpatria: precios por edad+género leídos del Excel (col 13 "Precio Axa")
// Key: `${planId}_${edadBracket}_M` o `${planId}_${edadBracket}_F`
const axaPriceMap = new Map<string, number>();
// Planes que tienen precios AXA en la DB
const axaPlanIds = new Set<number>();

export interface PlanInfo {
  planId: number;
  aseguradora: string;
  nombre: string;
  precioBase: number;
}

const planInfo = new Map<number, PlanInfo>();

/** Encuentra el bracket de edad más cercano hacia abajo */
function resolveEdad(edad: number): number {
  const clamped = Math.min(Math.max(edad, EDAD_BRACKETS[0]), EDAD_BRACKETS[EDAD_BRACKETS.length - 1]);
  let best = EDAD_BRACKETS[0];
  for (const b of EDAD_BRACKETS) {
    if (b <= clamped) best = b;
    else break;
  }
  return best;
}

export function loadPricingData(dbPath?: string): void {
  const filePath = dbPath ?? path.resolve(__dirname, '../database2.2.xlsx');

  factorMap.clear();
  deptsByPlan.clear();
  epsByPlan.clear();
  knownDepts.clear();
  knownEps.clear();
  planInfo.clear();
  axaPriceMap.clear();
  axaPlanIds.clear();
  console.log('📊 Cargando base de datos de tarifas...');
  const wb = xlsx.readFile(filePath, { dense: true });
  const ws = wb.Sheets[wb.SheetNames[0]];
  const rows: any[][] = xlsx.utils.sheet_to_json(ws, { header: 1, raw: true, defval: null });

  let loaded = 0;
  for (let i = 1; i < rows.length; i++) {
    const row = rows[i];
    if (!row || row[1] == null) continue;

    const planId     = Number(row[1]);
    const nombre     = String(row[2] ?? '');
    const aseg       = String(row[3] ?? '');
    const edad       = Number(row[4]);
    const genero     = String(row[5] ?? '');
    const depto      = String(row[6] ?? '');
    const eps        = String(row[7] ?? '');
    const precioBase = Number(row[8]);
    const factor     = Number(row[9]);
    const precioAxa  = row[13] != null ? Number(row[13]) : null;

    // Factor key — género no afecta el factor (confirmado: Masc = Fem en toda la DB)
    const fKey = `${planId}_${edad}`;
    if (!factorMap.has(fKey)) factorMap.set(fKey, factor);

    // Precio AXA por edad y género (columna 13 "Precio Axa")
    if (precioAxa != null && precioAxa > 0) {
      const esFem = genero.toLowerCase().includes('fem') || genero.toLowerCase().includes('muj');
      const gKey = esFem ? 'F' : 'M';
      axaPriceMap.set(`${planId}_${edad}_${gKey}`, precioAxa);
      axaPlanIds.add(planId);
    }

    if (!planInfo.has(planId)) {
      planInfo.set(planId, { planId, aseguradora: aseg, nombre, precioBase });
    }

    if (!deptsByPlan.has(planId)) deptsByPlan.set(planId, new Set());
    deptsByPlan.get(planId)!.add(depto);
    if (depto !== 'Todos' && depto !== 'Todas') knownDepts.add(depto);

    if (!epsByPlan.has(planId)) epsByPlan.set(planId, new Set());
    epsByPlan.get(planId)!.add(eps);
    if (eps !== 'Todos' && eps !== 'Todas') knownEps.add(eps);

    loaded++;
  }

  console.log(`✅ ${loaded} tarifas cargadas para ${planInfo.size} planes`);
  console.log(`   AXA Colpatria: ${axaPlanIds.size} planes con precio especial (${axaPriceMap.size} entradas)`);
  console.log(`   Edades: ${EDAD_BRACKETS.join(', ')}`);
}

export function getPrice(
  planId: number,
  edad: number,
  genero: string,
  _departamento: string,
  _eps: string
): number | null {
  // AXA Colpatria: precio por columna "Precio Axa" del Excel (edad + género)
  // Se evalúa ANTES de planInfo para cubrir planes sin entrada estándar en la BD
  if (axaPlanIds.has(planId)) {
    const edadBracket = resolveEdad(edad);
    const esFemenino = genero.toLowerCase().includes('fem') || genero.toLowerCase().includes('muj');
    const gKey = esFemenino ? 'F' : 'M';
    const axaPrice = axaPriceMap.get(`${planId}_${edadBracket}_${gKey}`);
    if (axaPrice != null) return axaPrice;
  }

  const info = planInfo.get(planId);
  if (!info) return null;

  // Resto de planes: precioBase × factor de edad
  const edadBracket = resolveEdad(edad);
  const factor = factorMap.get(`${planId}_${edadBracket}`);
  if (factor == null) return null;

  return Math.round(info.precioBase * factor);
}

export function getAvailableDepts(planId: number): string[] {
  return [...(deptsByPlan.get(planId) ?? [])].sort();
}

export function getAvailableEps(planId: number): string[] {
  return [...(epsByPlan.get(planId) ?? [])].sort();
}

export function isPlanAvailable(planId: number, departamento: string, eps: string): boolean {
  // Planes AXA con precios especiales en el Excel tienen cobertura nacional
  if (axaPlanIds.has(planId)) return true;

  const deptos = deptsByPlan.get(planId);
  const epsSet = epsByPlan.get(planId);
  if (!deptos || !epsSet) return false;

  // "Todos"/"Todas" en la DB = cobertura nacional
  const planEsNacional = deptos.has('Todos') || deptos.has('Todas');
  if (planEsNacional) return true;

  // Si el departamento solicitado NO existe en ningún plan de la DB,
  // no lo bloqueamos — la DB es incompleta, no el plan
  const deptOk = !departamento
    || !knownDepts.has(departamento)   // depto fuera del catálogo → no restringir
    || deptos.has(departamento);

  const epsOk = !eps
    || epsSet.has('Todos') || epsSet.has('Todas')
    || !knownEps.has(eps)              // EPS fuera del catálogo → no restringir
    || epsSet.has(eps);

  return deptOk && epsOk;
}

export function getAllPlans(): PlanInfo[] {
  return [...planInfo.values()].sort((a, b) => a.planId - b.planId);
}

export function getAllDepts(): string[] {
  const all = new Set<string>();
  for (const set of deptsByPlan.values())
    for (const d of set) if (d !== 'Todos' && d !== 'Todas') all.add(d);
  return [...all].sort();
}

export function getAllEps(): string[] {
  const all = new Set<string>();
  for (const set of epsByPlan.values())
    for (const e of set) if (e !== 'Todos' && e !== 'Todas') all.add(e);
  return [...all].sort();
}

export { EDAD_BRACKETS, resolveEdad };
