/**
 * Tabela B.1 — Anexo B (normativo) — Fator estatístico S₃ para
 * probabilidade Pₘ e vida útil da edificação.
 *
 * S₃ = 0,54 · (-ln(1 - Pₘ))^(-1/7) · m^(1/7)
 *
 * Valores pré-calculados conforme publicação oficial.
 *
 * Fonte: NBR 6123:2023, p. 94 (Anexo B, Tabela B.1).
 * Última auditoria: 2026-07-07 — ⚠️ PENDENTE: conferir valores exatos
 *   da grade Pₘ × m (OCR com pequenas inconsistências numéricas).
 *   A função analítica `calculateS3Analytical` é a referência confiável.
 */

export const PM_VALUES = [0.10, 0.20, 0.50, 0.63, 0.75, 0.90] as const;
export type PmValue = (typeof PM_VALUES)[number];

export const LIFE_VALUES = [2, 10, 25, 50, 100, 200] as const;
export type LifeYears = (typeof LIFE_VALUES)[number];

const TABLE_B1: Readonly<Record<LifeYears, Readonly<Record<PmValue, number>>>> = {
  2: { 0.10: 0.66, 0.20: 0.76, 0.50: 0.64, 0.63: 0.60, 0.75: 0.57, 0.90: 0.53 },
  10: { 0.10: 1.10, 0.20: 0.98, 0.50: 0.82, 0.63: 0.78, 0.75: 0.74, 0.90: 0.68 },
  25: { 0.10: 1.27, 0.20: 1.13, 0.50: 0.95, 0.63: 0.90, 0.75: 0.85, 0.90: 0.79 },
  50: { 0.10: 1.42, 0.20: 1.26, 0.50: 1.06, 0.63: 1.00, 0.75: 0.95, 0.90: 0.88 },
  100: { 0.10: 1.58, 0.20: 1.41, 0.50: 1.18, 0.63: 1.11, 0.75: 1.06, 0.90: 0.98 },
  200: { 0.10: 1.74, 0.20: 1.57, 0.50: 1.31, 0.63: 1.24, 0.75: 1.18, 0.90: 1.08 },
};

function clampPm(pm: number): PmValue {
  if (pm <= PM_VALUES[0]) return PM_VALUES[0];
  if (pm >= PM_VALUES[PM_VALUES.length - 1]) return PM_VALUES[PM_VALUES.length - 1];
  let best: PmValue = PM_VALUES[0];
  let bestDiff = Infinity;
  for (const cand of PM_VALUES) {
    const d = Math.abs(cand - pm);
    if (d < bestDiff) {
      bestDiff = d;
      best = cand;
    }
  }
  return best;
}

function clampLife(m: number): LifeYears {
  if (m <= LIFE_VALUES[0]) return LIFE_VALUES[0];
  if (m >= LIFE_VALUES[LIFE_VALUES.length - 1]) return LIFE_VALUES[LIFE_VALUES.length - 1];
  let best: LifeYears = LIFE_VALUES[0];
  let bestDiff = Infinity;
  for (const cand of LIFE_VALUES) {
    const d = Math.abs(cand - m);
    if (d < bestDiff) {
      bestDiff = d;
      best = cand;
    }
  }
  return best;
}

/**
 * S₃ conforme probabilidade Pₘ e vida útil m (anos).
 * Para (Pₘ, m) não tabelados, aplica clamp no par mais próximo.
 */
export function getS3ByPmAndLife(pm: number, lifeYears: number): number {
  const p = clampPm(pm);
  const m = clampLife(lifeYears);
  return TABLE_B1[m][p];
}

/** Cálculo analítico pela fórmula (para casos fora da grade) */
export function calculateS3Analytical(pm: number, lifeYears: number): number {
  if (pm <= 0 || pm >= 1) throw new Error('Pₘ deve estar em (0, 1)');
  if (lifeYears <= 0) throw new Error('Vida útil deve ser > 0');
  const v = 0.54 * Math.pow(-Math.log(1 - pm), -1 / 7) * Math.pow(lifeYears, 1 / 7);
  return Number(v.toFixed(3));
}