/**
 * Strategy — reticulados planos isolados (NBR 6123:2023, sec. 8.3)
 * e reticulados planos múltiplos (sec. 8.4).
 *
 * Implementação baseada nos gráficos das Figuras 12, 13 e 14.
 * Usa o índice de área exposta φ e o tipo de barras (faces planas ou circulares).
 */

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

/** Figura 12 — Ca para reticulado plano de barras de faces planas */
const PHI_FLAT = [0.05, 0.1, 0.15, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0] as const;
const PHI_BY_PLANE: Readonly<Record<number, number>> = {
  0.05: 3.6, 0.1: 3.0, 0.15: 2.7, 0.2: 2.5, 0.3: 2.2, 0.4: 2.0, 0.5: 1.85, 0.6: 1.75, 0.7: 1.65, 0.8: 1.55, 0.9: 1.5, 1.0: 1.4,
};

export interface TrussLatticeInput {
  /** Tipo de barras */
  barType: 'flat' | 'circular';
  /** Índice de área exposta φ */
  phi: number;
  /** Área frontal efetiva Ae (m²) */
  ae: number;
  /** Reynolds (apenas para circulares) */
  re?: number;
  /** Pressão dinâmica q (kN/m²) */
  q: number;
  /** Número de reticulados paralelos (1 para isolado) */
  numLattices: number;
  /** Fator de proteção η (Figura 14) — apenas se numLattices > 1 */
  eta?: number;
}

export interface TrussLatticeResult {
  ca: number;
  can: number;
  forceKN: number;
  /** Fator η efetivo usado */
  etaEffective: number;
}

/** Figura 14 — fator de proteção η em função de φ e afastamento e/hp */
const PHI_FOR_ETA = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7] as const;
const EH_FOR_ETA = [0.5, 1, 2, 3, 4, 5, 8, 10] as const;

const ETA_VALUES: Readonly<Record<number, Readonly<Record<number, number>>>> = {
  0.1: { 0.5: 1, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 8: 1, 10: 1 },
  0.2: { 0.5: 0.95, 1: 0.9, 2: 0.8, 3: 0.7, 4: 0.65, 5: 0.6, 8: 0.55, 10: 0.5 },
  0.3: { 0.5: 0.9, 1: 0.85, 2: 0.7, 3: 0.55, 4: 0.5, 5: 0.45, 8: 0.4, 10: 0.35 },
  0.4: { 0.5: 0.85, 1: 0.75, 2: 0.6, 3: 0.45, 4: 0.4, 5: 0.35, 8: 0.3, 10: 0.25 },
  0.5: { 0.5: 0.8, 1: 0.65, 2: 0.5, 3: 0.4, 4: 0.32, 5: 0.28, 8: 0.22, 10: 0.18 },
  0.6: { 0.5: 0.7, 1: 0.55, 2: 0.4, 3: 0.32, 4: 0.25, 5: 0.22, 8: 0.17, 10: 0.13 },
  0.7: { 0.5: 0.6, 1: 0.45, 2: 0.32, 3: 0.25, 4: 0.2, 5: 0.17, 8: 0.13, 10: 0.1 },
};

function caForFlatLattice(phi: number): number {
  // Para reticulado plano, Ca é função apenas de φ
  const xClamped = Math.max(0.05, Math.min(1.0, phi));
  const table = PHI_FLAT.map((p) => PHI_BY_PLANE[p]);
  const grid = {
    xs: PHI_FLAT,
    ys: [1] as readonly number[],
    values: [table],
  };
  return bilinearInterp(grid, xClamped, 1);
}

function caForCircularLattice(phi: number, re: number): number {
  // Tabela simplificada — Figura 13
  // Ca aumenta com φ e depende do regime de Re
  const baseCa = re < 4.2e5 ? 1.4 : re < 2.3e6 ? 0.7 : 0.6;
  const phiFactor = 0.5 + phi * 1.5;
  return Number((baseCa * phiFactor).toFixed(2));
}

export function calculateTrussLattice(input: TrussLatticeInput): TrussLatticeResult {
  const { barType, phi, ae, re = 0, q, numLattices } = input;

  const ca =
    barType === 'flat'
      ? caForFlatLattice(phi)
      : caForCircularLattice(phi, re);

  let can = ca;
  let etaEffective = 1;
  if (numLattices > 1) {
    // Fator de proteção η conforme φ (Tabela/Figura 14)
    const phiClamped = Math.max(0.1, Math.min(0.7, phi));
    const grid = {
      xs: EH_FOR_ETA,
      ys: PHI_FOR_ETA,
      values: PHI_FOR_ETA.map((p) => EH_FOR_ETA.map((e) => ETA_VALUES[p][e])),
    };
    // η decresce com afastamento; para simplificar usamos apenas φ
    etaEffective = bilinearInterp(grid, 5, phiClamped); // aproximado para e/hp médio
    can = ca * (1 + (numLattices - 1) * etaEffective);
  }

  const forceKN = Number((can * q * ae).toFixed(3));
  return { ca, can, forceKN, etaEffective };
}