import { describe, it, expect } from 'vitest';
import { calculateCylinder } from '../modules/cylinder';
import { calculateTower } from '../modules/tower';
import { calculateVault } from '../modules/vault';
import { calculateDome } from '../modules/dome';
import { calculateTrussLattice } from '../modules/truss';
import { calculateBridgeDeckForces } from '../modules/bridge';
import { getWallCpeOfficial, getRoofCpeOfficial } from '../coefficients';

describe('Audit Simulations for NBR 6123:2023 Models', () => {
  it('Simulates Cylinder model with various dimensions and roughness', () => {
    const dValues = [0.1, 1, 10, 50];
    const hValues = [1, 10, 100, 300];
    const vkValues = [10, 30, 50, 70];
    
    let anomalies = 0;
    
    for (const d of dValues) {
      for (const h of hValues) {
        for (const vk of vkValues) {
          for (const surface of ['smooth', 'rough'] as const) {
            for (const endType of ['closed', 'open-top', 'open-bottom', 'open-both'] as const) {
              const res = calculateCylinder({ d, h, vk, surface, endType, baseCpi: 0.2 });
              
              if (isNaN(res.forcePerHeightKN_m) || isNaN(res.cpi) || res.profile.some(p => isNaN(p.cpe))) {
                console.error('NaN in cylinder:', { d, h, vk, surface, endType });
                anomalies++;
              }
              if (res.cpi > 1.0 || res.cpi < -1.0) {
                console.error('Out of bounds Cpi in cylinder:', res.cpi, { endType });
                anomalies++;
              }
              expect(res.hOverD).toBe(h / d);
            }
          }
        }
      }
    }
    expect(anomalies).toBe(0);
  });

  it('Simulates Tower model', () => {
    const phis = [0.01, 0.05, 0.2, 0.5, 0.9, 1.5]; // 0.01 under, 1.5 over
    const qValues = [0.5, 1.0, 3.0];
    const aeValues = [10, 100];
    let anomalies = 0;

    for (const phi of phis) {
      for (const q of qValues) {
        for (const ae of aeValues) {
          for (const section of ['square', 'triangular'] as const) {
            for (const barType of ['flat', 'circular'] as const) {
              for (const alpha of [0, 45, 90] as const) {
                const res = calculateTower({ section, barType, phi, aFace: ae, alphaWind: alpha, q, re: 1e5 });
                
                if (isNaN(res.ca) || isNaN(res.forceKN)) {
                  console.error('NaN in tower:', { section, barType, phi });
                  anomalies++;
                }
                if (res.ca > 4.5 || res.ca < 0) {
                  console.error('Unusual Ca in tower:', res.ca, { section, barType, phi });
                  anomalies++;
                }
              }
            }
          }
        }
      }
    }
    expect(anomalies).toBe(0);
  });

  it('Simulates Vault model', () => {
    const fValues = [1, 5, 20];
    const lValues = [5, 20, 100]; // fl from 0.01 to 4
    const vkValues = [30, 50];
    let anomalies = 0;

    for (const f of fValues) {
      for (const l of lValues) {
        for (const vk of vkValues) {
          for (const regime of ['laminar-rough', 'turbulent-51', 'turbulent-52'] as const) {
            const res = calculateVault({ f, l, b: 20, vk, regime, cpi: 0 });
            if (isNaN(res.q)) anomalies++;
            for (const cpe of Object.values(res.windPerpendicular)) {
              if (isNaN(cpe)) {
                console.error('NaN Cpe in vault perp:', { f, l, regime });
                anomalies++;
              }
            }
            for (const cpe of Object.values(res.windParallel)) {
              if (isNaN(cpe)) {
                console.error('NaN Cpe in vault parallel:', { f, l, regime });
                anomalies++;
              }
            }
          }
        }
      }
    }
    expect(anomalies).toBe(0);
  });

  it('Simulates Dome model', () => {
    const dValues = [5, 20, 50];
    const fValues = [1, 5, 20]; // f/d = 0.02 to 4
    let anomalies = 0;

    for (const d of dValues) {
      for (const f of fValues) {
        for (const type of ['on-ground', 'on-cylinder'] as const) {
          const res = calculateDome({ d, f, vk: 40, type, cpi: 0 });
          if (isNaN(res.cpeBarlavento) || isNaN(res.cpeTopo) || isNaN(res.cpeLateral)) {
            console.error('NaN Cpe in dome:', { d, f, type });
            anomalies++;
          }
        }
      }
    }
    expect(anomalies).toBe(0);
  });

  it('Simulates Bridge model', () => {
    const bValues = [5, 15, 30];
    const hegValues = [0.5, 2, 5, 10]; // b/heg ratio = 0.5 to 60
    let anomalies = 0;

    for (const b of bValues) {
      for (const heg of hegValues) {
        const res = calculateBridgeDeckForces({ width: b, heg, vk: 40, q: 1.0 });
        if (isNaN(res.cx) || isNaN(res.cz) || isNaN(res.fxPerLength)) {
          console.error('NaN in bridge forces:', { b, heg });
          anomalies++;
        }
        if (Math.abs(res.cz) > 1.501) {
          console.error('Bridge Cz > 1.5:', res.cz, { b, heg, ratio: b/heg });
          anomalies++;
        }
      }
    }
    expect(anomalies).toBe(0);
  });

  it('Simulates Truss model', () => {
    const phis = [0.05, 0.5, 0.95];
    const nums = [1, 2, 5];
    let anomalies = 0;
    for (const phi of phis) {
      for (const numLattices of nums) {
        const res = calculateTrussLattice({ barType: 'flat', phi, ae: 10, q: 1, numLattices });
        if (isNaN(res.can)) anomalies++;
      }
    }
    expect(anomalies).toBe(0);
  });

  it('Simulates Warehouses / Roofs', () => {
    const a = 20, b = 10, h = 5;
    const res0 = getWallCpeOfficial(a, b, h, 0);
    const res90 = getWallCpeOfficial(a, b, h, 90);
    expect(res0.A).toBeDefined();
    expect(res90.A).toBeDefined();

    const thetas = [0, 5, 10, 15, 20, 30, 45, 60, 75, 80]; // Testing angle limits
    let anomalies = 0;
    for (const theta of thetas) {
      try {
        const roof0 = getRoofCpeOfficial(a, b, h, theta, 0);
        const roof90 = getRoofCpeOfficial(a, b, h, theta, 90);
        if (isNaN(roof0.E) || isNaN(roof90.E)) anomalies++;
      } catch (e) {
        console.error('Exception in roof calculation at theta', theta, e);
        anomalies++;
      }
    }
    expect(anomalies).toBe(0);
  });
});
