<?php

class ForestCalculations {
    
    /**
     * Calcula el área basal total por hectárea
     * @param array $registros Array de registros de campo con dap_cm
     * @param float $areaRodal Área del rodal en hectáreas
     * @return float Área basal en m²/ha
     */
    public static function calcularAreaBasal($registros, $areaRodal) {
        self::validarDatos($registros);
        
        $sumaAreaBasal = 0;
        
        foreach ($registros as $registro) {
            $radio = $registro['dap_cm'] / 2 / 100; // convertir a metros
            $areaBasalArbol = pi() * pow($radio, 2);
            $sumaAreaBasal += $areaBasalArbol;
        }
        
        return round($sumaAreaBasal / $areaRodal, 2);
    }
    
    /**
     * Calcula el volumen total por hectárea
     * @param array $registros Array de registros de campo con dap_cm y altura_m
     * @param float $areaRodal Área del rodal en hectáreas
     * @return float Volumen en m³/ha
     */
    public static function calcularVolumen($registros, $areaRodal) {
        $volumenTotal = 0;
        
        foreach ($registros as $registro) {
            $areaBasalArbol = pi() * pow(($registro['dap_cm'] / 2 / 100), 2);
            $volumenArbol = $areaBasalArbol * $registro['altura_m'] * 0.7; // Factor de forma
            $volumenTotal += $volumenArbol;
        }
        
        return round($volumenTotal / $areaRodal, 2);
    }
    
    /**
     * Calcula el conteo total de árboles
     * @param array $registros Array de registros de campo
     * @return int Número total de árboles
     */
    public static function contarArboles($registros) {
        return count($registros);
    }
    
    /**
     * Calcula el DAP promedio
     * @param array $registros Array de registros de campo con dap_cm
     * @return float DAP promedio en cm
     */
    public static function calcularDAPPromedio($registros) {
        if (empty($registros)) {
            return 0;
        }
        
        $sumaDap = 0;
        foreach ($registros as $registro) {
            $sumaDap += $registro['dap_cm'];
        }
        
        return round($sumaDap / count($registros), 2);
    }
    
    /**
     * Calcula la altura promedio
     * @param array $registros Array de registros de campo con altura_m
     * @return float Altura promedio en metros
     */
    public static function calcularAlturaPromedio($registros) {
        if (empty($registros)) {
            return 0;
        }
        
        $sumaAltura = 0;
        foreach ($registros as $registro) {
            $sumaAltura += $registro['altura_m'];
        }
        
        return round($sumaAltura / count($registros), 2);
    }
    
    /**
     * Calcula todas las métricas forestales para un rodal
     * @param array $registros Array de registros de campo
     * @param float $areaRodal Área del rodal en hectáreas
     * @return array Array con todas las métricas calculadas
     */
    public static function calcularMetricasCompletas($registros, $areaRodal) {
        $metricas = [
            'conteo_arboles' => self::contarArboles($registros),
            'dap_promedio' => self::calcularDAPPromedio($registros),
            'altura_promedio' => self::calcularAlturaPromedio($registros),
            'area_basal' => self::calcularAreaBasal($registros, $areaRodal),
            'volumen' => self::calcularVolumen($registros, $areaRodal),
            'area_rodal' => $areaRodal
        ];
        
        // Agregar análisis por especies si hay datos
        if (!empty($registros)) {
            $metricas['especies'] = self::calcularMetricasPorEspecie($registros);
        }
        
        return $metricas;
    }
    
    /**
     * Calcula métricas agrupadas por especie
     * @param array $registros Array de registros de campo
     * @return array Array con métricas por especie
     */
    public static function calcularMetricasPorEspecie($registros) {
        $especiesData = [];
        $totalArboles = count($registros);
        
        // Agrupar registros por especie
        foreach ($registros as $registro) {
            $especieId = $registro['especie_id'] ?? null;
            $especieNombre = $registro['especie_nombre'] ?? 'Especie Desconocida';
            $especieCientifico = $registro['especie_cientifico'] ?? '';
            
            if (!isset($especiesData[$especieId])) {
                $especiesData[$especieId] = [
                    'especie_id' => $especieId,
                    'nombre_comun' => $especieNombre,
                    'nombre_cientifico' => $especieCientifico,
                    'registros' => []
                ];
            }
            
            $especiesData[$especieId]['registros'][] = $registro;
        }
        
        // Calcular métricas para cada especie
        $especiesMetricas = [];
        foreach ($especiesData as $especieId => $data) {
            $registrosEspecie = $data['registros'];
            $cantidad = count($registrosEspecie);
            $porcentaje = ($cantidad / $totalArboles) * 100;
            
            $especiesMetricas[] = [
                'especie_id' => $especieId,
                'nombre_comun' => $data['nombre_comun'],
                'nombre_cientifico' => $data['nombre_cientifico'],
                'cantidad' => $cantidad,
                'porcentaje' => round($porcentaje, 2),
                'dap_promedio' => self::calcularDAPPromedio($registrosEspecie),
                'altura_promedio' => self::calcularAlturaPromedio($registrosEspecie)
            ];
        }
        
        // Ordenar por cantidad descendente
        usort($especiesMetricas, function($a, $b) {
            return $b['cantidad'] - $a['cantidad'];
        });
        
        return $especiesMetricas;
    }
    
    /**
     * Calcula promedios de DAP y altura
     * @param array $registros Array de registros de campo
     * @return array Array con promedios y total de árboles
     */
    public static function calcularPromedios($registros) {
        if (empty($registros)) {
            return [
                'dap_promedio' => 0,
                'altura_promedio' => 0,
                'total_arboles' => 0
            ];
        }
        
        return [
            'dap_promedio' => self::calcularDAPPromedio($registros),
            'altura_promedio' => self::calcularAlturaPromedio($registros),
            'total_arboles' => count($registros)
        ];
    }
    
    /**
     * Calcula distribución diamétrica
     * @param array $registros Array de registros de campo
     * @return array Array con clases diamétricas y frecuencias
     */
    public static function calcularDistribucionDiametrica($registros) {
        if (empty($registros)) {
            return ['clases' => [], 'frecuencias' => []];
        }
        
        // Definir clases diamétricas (cada 10 cm)
        $clases = [];
        $frecuencias = [];
        
        // Encontrar rango de DAP
        $daps = array_column($registros, 'dap_cm');
        $minDap = min($daps);
        $maxDap = max($daps);
        
        // Crear clases de 10 cm
        $claseInicio = floor($minDap / 10) * 10;
        $claseFin = ceil($maxDap / 10) * 10;
        
        for ($i = $claseInicio; $i < $claseFin; $i += 10) {
            $claseLabel = $i . '-' . ($i + 9.9);
            $clases[] = $claseLabel;
            $frecuencias[] = 0;
        }
        
        // Contar frecuencias
        foreach ($registros as $registro) {
            $dap = $registro['dap_cm'];
            $claseIndex = floor(($dap - $claseInicio) / 10);
            if ($claseIndex >= 0 && $claseIndex < count($frecuencias)) {
                $frecuencias[$claseIndex]++;
            }
        }
        
        return [
            'clases' => $clases,
            'frecuencias' => $frecuencias
        ];
    }
    
    /**
     * Calcula índices estructurales del bosque
     * @param array $registros Array de registros de campo
     * @return array Array con índices estructurales
     */
    public static function calcularIndicesEstructurales($registros) {
        if (empty($registros)) {
            return [
                'coeficiente_variacion_dap' => 0,
                'coeficiente_variacion_altura' => 0,
                'indice_diversidad_estructural' => 0
            ];
        }
        
        $daps = array_column($registros, 'dap_cm');
        $alturas = array_column($registros, 'altura_m');
        
        // Calcular coeficiente de variación para DAP
        $promedioDap = array_sum($daps) / count($daps);
        $varianzaDap = 0;
        foreach ($daps as $dap) {
            $varianzaDap += pow($dap - $promedioDap, 2);
        }
        $desviacionDap = sqrt($varianzaDap / count($daps));
        $cvDap = ($desviacionDap / $promedioDap) * 100;
        
        // Calcular coeficiente de variación para altura
        $promedioAltura = array_sum($alturas) / count($alturas);
        $varianzaAltura = 0;
        foreach ($alturas as $altura) {
            $varianzaAltura += pow($altura - $promedioAltura, 2);
        }
        $desviacionAltura = sqrt($varianzaAltura / count($alturas));
        $cvAltura = ($desviacionAltura / $promedioAltura) * 100;
        
        // Índice de diversidad estructural (simplificado)
        $indiceDiversidad = ($cvDap + $cvAltura) / 2;
        
        return [
            'coeficiente_variacion_dap' => round($cvDap, 2),
            'coeficiente_variacion_altura' => round($cvAltura, 2),
            'indice_diversidad_estructural' => round($indiceDiversidad, 2)
        ];
    }
    
    /**
     * Calcula área basal por especie
     * @param array $registros Array de registros de campo con especie
     * @param float $areaRodal Área del rodal en hectáreas
     * @return array Array con área basal por especie
     */
    public static function calcularAreaBasalPorEspecie($registros, $areaRodal) {
        if (empty($registros)) {
            return [];
        }
        
        $areaPorEspecie = [];
        
        foreach ($registros as $registro) {
            $especie = $registro['especie'] ?? 'Desconocida';
            $radio = $registro['dap_cm'] / 2 / 100; // convertir a metros
            $areaBasalArbol = pi() * pow($radio, 2);
            
            if (!isset($areaPorEspecie[$especie])) {
                $areaPorEspecie[$especie] = 0;
            }
            
            $areaPorEspecie[$especie] += $areaBasalArbol;
        }
        
        // Convertir a m²/ha
        foreach ($areaPorEspecie as $especie => $area) {
            $areaPorEspecie[$especie] = round($area / $areaRodal, 2);
        }
        
        return $areaPorEspecie;
    }
    
    /**
     * Valida datos de entrada para cálculos
     * @param array $registros Array de registros de campo
     * @throws InvalidArgumentException Si los datos son inválidos
     */
    public static function validarDatos($registros) {
        foreach ($registros as $registro) {
            if (isset($registro['dap_cm']) && $registro['dap_cm'] <= 0) {
                throw new InvalidArgumentException('DAP debe ser mayor a 0');
            }
            if (isset($registro['altura_m']) && $registro['altura_m'] <= 0) {
                throw new InvalidArgumentException('Altura debe ser mayor a 0');
            }
        }
    }
    
    /**
     * Genera datos para exportación CSV con formato INAB
     * @param array $registros Array de registros de campo
     * @param array $rodalInfo Información del rodal
     * @param array $proyectoInfo Información del proyecto
     * @return array Array con datos estructurados para CSV
     */
    public static function generarDatosCSV($registros, $rodalInfo, $proyectoInfo) {
        $metricas = self::calcularMetricasCompletas($registros, $rodalInfo['area_ha']);
        
        $datosCSV = [];
        
        // Encabezado del reporte
        $datosCSV[] = [
            'SISTEMA DE INVENTARIO FORESTAL - GUATEMALA',
            '', '', '', '', '', ''
        ];
        $datosCSV[] = [
            'INSTITUTO NACIONAL DE BOSQUES (INAB)',
            '', '', '', '', '', ''
        ];
        $datosCSV[] = ['', '', '', '', '', '', ''];
        
        // Información del proyecto
        $datosCSV[] = [
            'INFORMACIÓN DEL PROYECTO',
            '', '', '', '', '', ''
        ];
        $datosCSV[] = [
            'Proyecto:', $proyectoInfo['nombre_proyecto'],
            'Finca:', $proyectoInfo['nombre_finca'],
            'Departamento:', $proyectoInfo['departamento'],
            'Municipio:', $proyectoInfo['municipio']
        ];
        $datosCSV[] = [
            'Propietario:', $proyectoInfo['nombre_propietario'],
            'Regente:', $proyectoInfo['nombre_regente_forestal'],
            '', '', '', '', ''
        ];
        $datosCSV[] = ['', '', '', '', '', '', ''];
        
        // Información del rodal
        $datosCSV[] = [
            'INFORMACIÓN DEL RODAL',
            '', '', '', '', '', ''
        ];
        $datosCSV[] = [
            'Rodal:', $rodalInfo['nombre_rodal'],
            'Área (ha):', $rodalInfo['area_ha'],
            '', '', '', '', ''
        ];
        $datosCSV[] = ['', '', '', '', '', '', ''];
        
        // Resumen de métricas
        $datosCSV[] = [
            'RESUMEN DE MÉTRICAS FORESTALES',
            '', '', '', '', '', ''
        ];
        $datosCSV[] = [
            'Métrica', 'Valor', 'Unidad', '', '', '', ''
        ];
        $datosCSV[] = [
            'Número total de árboles', $metricas['conteo_arboles'], 'árboles', '', '', '', ''
        ];
        $datosCSV[] = [
            'DAP promedio', $metricas['dap_promedio'], 'cm', '', '', '', ''
        ];
        $datosCSV[] = [
            'Altura promedio', $metricas['altura_promedio'], 'm', '', '', '', ''
        ];
        $datosCSV[] = [
            'Área basal', $metricas['area_basal'], 'm²/ha', '', '', '', ''
        ];
        $datosCSV[] = [
            'Volumen', $metricas['volumen'], 'm³/ha', '', '', '', ''
        ];
        $datosCSV[] = ['', '', '', '', '', '', ''];
        
        // Detalle de registros
        $datosCSV[] = [
            'DETALLE DE REGISTROS DE CAMPO',
            '', '', '', '', '', ''
        ];
        $datosCSV[] = [
            'No.', 'Parcela', 'Especie', 'DAP (cm)', 'Altura (m)', 'Condición', 'Fecha'
        ];
        
        $contador = 1;
        foreach ($registros as $registro) {
            $datosCSV[] = [
                $contador,
                $registro['numero_parcela'],
                $registro['especie'] ?? 'N/A',
                $registro['dap_cm'],
                $registro['altura_m'],
                $registro['condicion_arbol'],
                date('Y-m-d', strtotime($registro['fecha_captura']))
            ];
            $contador++;
        }
        
        return $datosCSV;
    }
}