/**
 * Tabela 23 — Coeficientes de força Cf para muros e placas retangulares
 * (NBR 6123:2023, sec. 7.1).
 *
 * Casos:
 *  - Escoamento 2D (ℓ/hₐ ≥ 60) sem placas de extremidade: α=90° e α=50°
 *  - Com placas de extremidade (ℓ/hₐ = 10): α=90° e α=50°
 *  - Caso intermediário (ℓ/hₐ entre 10 e 60): interpolar
 *
 * Fonte: NBR 6123:2023, p. 48 (Tabela 23).
 * Última auditoria: 2026-07-07 — valores oficiais confirmados.
 */

import { linearInterp1D } from '../log-interp';

const LH_RATIOS = [10, 60, 1000] as const;

export interface SignInput {
  /** Comprimento ℓ (m) */
  length: number;
  /** Altura hₐ (m) */
  height: number;
  /** Ângulo de incidência do vento (graus) */
  alpha: 90 | 50;
  /** true se houver placas de extremidade */
  hasEndPlates: boolean;
  /** Distância do solo (m) */
  groundClearance: number;
}

export interface SignResult {
  lhRatio: number;
  cf: number;
  e: number;
  /** Área frontal efetiva (m²) */
  areaEffective: number;
  /** Ponto de aplicação da força em altura */
  applicationPoint: number;
  /** Força F = Cf · q · A (kN) */
  forceKN: number;
  /** Momento de tombamento em relação à base da placa (kNm) */
  momentBaseKNm: number;
  /** Momento de tombamento em relação ao solo (kNm) */
  momentGroundKNm: number;
}

export function calculateSign(
  input: SignInput,
  q: number,
): SignResult {
  const { length, height, alpha, hasEndPlates, groundClearance } = input;
  const lh = length / height;
  const eRatio = groundClearance / height;

  // Valores oficiais da Tab. 23:
  //  - Sem placas de extremidade (escoamento 2D), ℓ/hₐ ≥ 60: Cf = 1,2
  //  - Sem placas, α=50°: Cf = 1,6
  //  - Com placas de extremidade, ℓ/hₐ = 10: Cf = 1,2
  //  - Com placas, α=50°: Cf = 1,8
  const cfWithoutPlates_90 = 1.2;
  const cfWithoutPlates_50 = 1.6;
  const cfWithPlates_90 = 1.2;
  const cfWithPlates_50 = 1.8;

  let cf: number;
  if (hasEndPlates) {
    cf = alpha === 90 ? cfWithPlates_90 : cfWithPlates_50;
  } else {
    if (alpha === 90) {
      cf = lh >= 60 ? cfWithoutPlates_90 : linearInterp1D(LH_RATIOS, [cfWithoutPlates_90, cfWithoutPlates_90, cfWithoutPlates_90], Math.max(lh, 10));
    } else {
      cf = lh >= 60 ? cfWithoutPlates_50 : linearInterp1D(LH_RATIOS, [cfWithoutPlates_50, cfWithoutPlates_50, cfWithoutPlates_50], Math.max(lh, 10));
    }
  }

  // Posição do centro de pressão em função da relação com o solo
  let e: number;
  if (hasEndPlates) {
    if (eRatio < 0.25) {
      e = height * 0.4;
    } else if (eRatio < 2) {
      e = height * (0.4 + 0.2 * (eRatio - 0.25) / 1.75);
    } else {
      e = height / 2;
    }
  } else {
    if (eRatio < 0.25) {
      e = height * 0.3;
    } else if (eRatio < 2) {
      e = height * 0.5;
    } else {
      e = height / 2;
    }
  }

  const areaEffective = length * height;
  const forceKN = Number((cf * q * areaEffective).toFixed(3));
  
  const momentBaseKNm = Number((forceKN * (height / 2)).toFixed(3));
  const momentGroundKNm = Number((forceKN * (height / 2 + groundClearance)).toFixed(3));

  return {
    lhRatio: lh,
    cf,
    e,
    areaEffective,
    applicationPoint: e,
    forceKN,
    momentBaseKNm,
    momentGroundKNm,
  };
}