<?php

use PHPUnit\Framework\TestCase;

require_once __DIR__ . '/../../api/utils/ForestCalculations.php';

class ForestCalculationsTest extends TestCase
{
    private $sampleData;
    
    protected function setUp(): void
    {
        $this->sampleData = [
            [
                'dap_cm' => 25.5,
                'altura_m' => 15.2,
                'condicion_arbol' => 'Sano'
            ],
            [
                'dap_cm' => 30.0,
                'altura_m' => 18.5,
                'condicion_arbol' => 'Sano'
            ],
            [
                'dap_cm' => 22.3,
                'altura_m' => 12.8,
                'condicion_arbol' => 'Bifurcado'
            ]
        ];
    }

    public function testCalcularAreaBasal()
    {
        $areaRodal = 1.0; // 1 hectárea
        $areaBasal = ForestCalculations::calcularAreaBasal($this->sampleData, $areaRodal);
        
        // Verificar que el resultado es un número positivo
        $this->assertIsFloat($areaBasal);
        $this->assertGreaterThan(0, $areaBasal);
        
        // Verificar cálculo manual para el primer árbol
        $radio1 = 25.5 / 2 / 100; // 0.1275 m
        $areaEsperada1 = pi() * pow($radio1, 2);
        
        $this->assertGreaterThan($areaEsperada1, $areaBasal);
    }

    public function testCalcularVolumen()
    {
        $areaRodal = 1.0; // 1 hectárea
        $volumen = ForestCalculations::calcularVolumen($this->sampleData, $areaRodal);
        
        // Verificar que el resultado es un número positivo
        $this->assertIsFloat($volumen);
        $this->assertGreaterThan(0, $volumen);
        
        // El volumen debe ser mayor que el área basal (multiplicado por altura y factor)
        $areaBasal = ForestCalculations::calcularAreaBasal($this->sampleData, $areaRodal);
        $this->assertGreaterThan($areaBasal, $volumen);
    }

    public function testCalcularPromedios()
    {
        $promedios = ForestCalculations::calcularPromedios($this->sampleData);
        
        $this->assertArrayHasKey('dap_promedio', $promedios);
        $this->assertArrayHasKey('altura_promedio', $promedios);
        $this->assertArrayHasKey('total_arboles', $promedios);
        
        // Verificar cálculo de promedio DAP
        $dapEsperado = (25.5 + 30.0 + 22.3) / 3;
        $this->assertEquals(round($dapEsperado, 2), $promedios['dap_promedio']);
        
        // Verificar cálculo de promedio altura
        $alturaEsperada = (15.2 + 18.5 + 12.8) / 3;
        $this->assertEquals(round($alturaEsperada, 2), $promedios['altura_promedio']);
        
        // Verificar conteo total
        $this->assertEquals(3, $promedios['total_arboles']);
    }

    public function testCalcularDistribucionDiametrica()
    {
        $distribucion = ForestCalculations::calcularDistribucionDiametrica($this->sampleData);
        
        $this->assertIsArray($distribucion);
        $this->assertArrayHasKey('clases', $distribucion);
        $this->assertArrayHasKey('frecuencias', $distribucion);
        
        // Verificar que las frecuencias suman el total de árboles
        $totalFrecuencias = array_sum($distribucion['frecuencias']);
        $this->assertEquals(count($this->sampleData), $totalFrecuencias);
    }

    public function testCalcularIndicesEstructurales()
    {
        $indices = ForestCalculations::calcularIndicesEstructurales($this->sampleData);
        
        $this->assertArrayHasKey('coeficiente_variacion_dap', $indices);
        $this->assertArrayHasKey('coeficiente_variacion_altura', $indices);
        $this->assertArrayHasKey('indice_diversidad_estructural', $indices);
        
        // Los coeficientes de variación deben estar entre 0 y 100
        $this->assertGreaterThanOrEqual(0, $indices['coeficiente_variacion_dap']);
        $this->assertLessThanOrEqual(100, $indices['coeficiente_variacion_dap']);
    }

    public function testCalculosConDatosVacios()
    {
        $datosVacios = [];
        
        $areaBasal = ForestCalculations::calcularAreaBasal($datosVacios, 1.0);
        $volumen = ForestCalculations::calcularVolumen($datosVacios, 1.0);
        $promedios = ForestCalculations::calcularPromedios($datosVacios);
        
        $this->assertEquals(0, $areaBasal);
        $this->assertEquals(0, $volumen);
        $this->assertEquals(0, $promedios['total_arboles']);
    }

    public function testValidacionDatosInvalidos()
    {
        $datosInvalidos = [
            [
                'dap_cm' => -5, // DAP negativo
                'altura_m' => 15.2,
                'condicion_arbol' => 'Sano'
            ]
        ];
        
        $this->expectException(InvalidArgumentException::class);
        ForestCalculations::calcularAreaBasal($datosInvalidos, 1.0);
    }

    public function testCalcularAreaBasalPorEspecie()
    {
        $datosConEspecie = [
            [
                'dap_cm' => 25.5,
                'altura_m' => 15.2,
                'especie' => 'Pinus maximinoi',
                'condicion_arbol' => 'Sano'
            ],
            [
                'dap_cm' => 30.0,
                'altura_m' => 18.5,
                'especie' => 'Cupressus lusitanica',
                'condicion_arbol' => 'Sano'
            ],
            [
                'dap_cm' => 22.3,
                'altura_m' => 12.8,
                'especie' => 'Pinus maximinoi',
                'condicion_arbol' => 'Bifurcado'
            ]
        ];
        
        $areaPorEspecie = ForestCalculations::calcularAreaBasalPorEspecie($datosConEspecie, 1.0);
        
        $this->assertArrayHasKey('Pinus maximinoi', $areaPorEspecie);
        $this->assertArrayHasKey('Cupressus lusitanica', $areaPorEspecie);
        
        // Verificar que la suma de áreas por especie igual al área total
        $areaTotal = ForestCalculations::calcularAreaBasal($datosConEspecie, 1.0);
        $sumaPorEspecie = array_sum($areaPorEspecie);
        
        $this->assertEquals($areaTotal, $sumaPorEspecie, '', 0.01);
    }
}