/**
 * Tabela 7 — Cpe para telhados com duas águas simétricos em
 * edificações de planta retangular (NBR 6123:2023, sec. 6.1.1).
 *
 * Inclui zonas E, F, G, H do telhado + zonas I, J (platibanda/ático).
 *
 * Fonte: NBR 6123:2023, p. 21 (Tabela 7).
 *
 * A norma fornece 3 faixas de h/b:
 *  - h/b ≤ 1/2
 *  - 1/2 < h/b ≤ 3/2
 *  - 3/2 < h/b ≤ 6
 *
 * Para as zonas:
 *  - α = 90° (vento paralelo à cumeeira): Colunas EG e FH
 *  - α = 0° (vento perpendicular à cumeeira): Colunas EF e GH
 */

import { bilinearInterp } from '../bilinear-interp';

const THETA = [0, 5, 10, 15, 20, 30, 45, 60] as const;

type HbRange = 'low' | 'mid' | 'high';

/**
 * Colunas de Valores de Ce extraídas da Tabela 7.
 * Col 1: EG para α=90°
 * Col 2: FH para α=90°
 * Col 3: EF para α=0°
 * Col 4: GH para α=0°
 */
const TABLE_CE: Record<HbRange, Record<string, readonly number[]>> = {
  low: {
    //       0°    5°   10°   15°   20°   30°   45°   60°
    EG_90: [-0.8, -0.9, -1.2, -1.0, -0.4,    0, +0.3, +0.7],
    FH_90: [-0.4, -0.4, -0.4, -0.4, -0.4, -0.4, -0.5, -0.6],
    EF_0:  [-0.8, -0.8, -0.8, -0.8, -0.7, -0.7, -0.7, -0.7],
    GH_0:  [-0.4, -0.4, -0.6, -0.6, -0.6, -0.6, -0.6, -0.6],
  },
  mid: {
    EG_90: [-0.8, -0.9, -1.1, -1.0, -0.7, -0.2, +0.2, +0.6],
    FH_90: [-0.6, -0.6, -0.6, -0.6, -0.5, -0.5, -0.5, -0.5],
    EF_0:  [-1.0, -0.9, -0.8, -0.8, -0.8, -0.8, -0.8, -0.8],
    GH_0:  [-0.6, -0.6, -0.6, -0.6, -0.6, -0.8, -0.8, -0.8],
  },
  high: {
    EG_90: [-0.8, -0.8, -0.8, -0.8, -0.8, -1.0, -0.2, +0.5],
    FH_90: [-0.6, -0.6, -0.6, -0.6, -0.6, -0.5, -0.5, -0.5],
    EF_0:  [-0.9, -0.8, -0.8, -0.8, -0.8, -0.8, -0.8, -0.8],
    GH_0:  [-0.7, -0.8, -0.8, -0.8, -0.8, -0.7, -0.7, -0.7],
  },
};

/**
 * Valores I e J (platibanda/ático) — para vento α = 0° ou α = 90°.
 * Conforme NOTA 3 da Tabela 7:
 * Varia com a/b: a/b = 1 → mesmo valor de F e H; a/b ≥ 2 → Ce = -0.2.
 * Interpolação linear para 1 < a/b < 2.
 */
function getIJ(a: number, b: number, baseValue: number): { I: number; J: number } {
  const ab = a / Math.max(b, 0.001);
  if (ab <= 1) return { I: baseValue, J: baseValue };
  if (ab >= 2) return { I: -0.2, J: -0.2 };
  const t = ab - 1;
  const interp = baseValue + (-0.2 - baseValue) * t;
  return {
    I: Number(interp.toFixed(2)),
    J: Number(interp.toFixed(2)),
  };
}

function getHbRange(hOverB: number): HbRange {
  if (hOverB <= 0.5) return 'low';
  if (hOverB <= 1.5) return 'mid';
  return 'high';
}

function interpTheta(values: readonly number[], theta: number): number {
  const t = Math.max(THETA[0], Math.min(THETA[THETA.length - 1], theta));
  const grid = {
    xs: THETA,
    ys: [0],
    values: [values],
  };
  return bilinearInterp(grid, t, 0);
}

function lookupZone(
  hbRange: HbRange,
  colKey: string,
  theta: number,
): number {
  const values = TABLE_CE[hbRange][colKey];
  if (!values) return 0;
  return Number(interpTheta(values, theta).toFixed(2));
}

export interface RoofCpeZones {
  E: number;
  F: number;
  G: number;
  H: number;
  I: number;
  J: number;
}

export function getRoofCpeNBR6123(
  a: number,
  b: number,
  h: number,
  theta: number,
  windAngle: 0 | 90 = 0,
): RoofCpeZones {
  if (b <= 0) return { E: 0, F: 0, G: 0, H: 0, I: 0, J: 0 };
  const hOverB = h / b;
  const hbRange = getHbRange(hOverB);
  const tClamped = Math.max(THETA[0], Math.min(THETA[THETA.length - 1], theta));

  let E = 0, F = 0, G = 0, H = 0, baseIJ = 0;

  if (windAngle === 90) {
    // α = 90° (vento paralelo à cumeeira)
    // EG (bordo de ataque) e FH (meio)
    const eg = lookupZone(hbRange, 'EG_90', tClamped);
    const fh = lookupZone(hbRange, 'FH_90', tClamped);
    E = eg;
    G = eg;
    F = fh;
    H = fh;
    baseIJ = fh;
  } else {
    // α = 0° (vento perpendicular à cumeeira)
    // EF (água de barlavento) e GH (água de sotavento)
    const ef = lookupZone(hbRange, 'EF_0', tClamped);
    const gh = lookupZone(hbRange, 'GH_0', tClamped);
    E = ef;
    F = ef;
    G = gh;
    H = gh;
    baseIJ = gh; // J fica a sotavento
  }

  const { I, J } = getIJ(a, b, baseIJ);

  return { E, F, G, H, I, J };
}
