<?php
class FieldData {
    private $conn;
    private $table_name = "datos_campo";

    public $id;
    public $rodal_id;
    public $numero_parcela;
    public $fecha_captura;
    public $latitud;
    public $longitud;
    public $especie_id;
    public $dap_cm;
    public $altura_m;
    public $condicion_arbol;
    public $estado_sincronizacion;
    public $usuario_id;
    public $fecha_sincronizacion;

    public function __construct($db) {
        $this->conn = $db;
    }

    // Crear nuevo registro de campo
    public function create() {
        $query = "INSERT INTO " . $this->table_name . " 
                  (rodal_id, numero_parcela, latitud, longitud, especie_id, dap_cm, 
                   altura_m, condicion_arbol, estado_sincronizacion, usuario_id) 
                  VALUES (:rodal_id, :numero_parcela, :latitud, :longitud, :especie_id, 
                          :dap_cm, :altura_m, :condicion_arbol, :estado_sincronizacion, :usuario_id)";

        $stmt = $this->conn->prepare($query);

        // Sanitizar y validar datos
        $this->numero_parcela = intval($this->numero_parcela);
        $this->latitud = floatval($this->latitud);
        $this->longitud = floatval($this->longitud);
        $this->especie_id = intval($this->especie_id);
        $this->dap_cm = floatval($this->dap_cm);
        $this->altura_m = floatval($this->altura_m);
        $this->condicion_arbol = htmlspecialchars(strip_tags($this->condicion_arbol));
        $this->estado_sincronizacion = $this->estado_sincronizacion ?: 'Pendiente';

        // Bind de parámetros
        $stmt->bindParam(":rodal_id", $this->rodal_id);
        $stmt->bindParam(":numero_parcela", $this->numero_parcela);
        $stmt->bindParam(":latitud", $this->latitud);
        $stmt->bindParam(":longitud", $this->longitud);
        $stmt->bindParam(":especie_id", $this->especie_id);
        $stmt->bindParam(":dap_cm", $this->dap_cm);
        $stmt->bindParam(":altura_m", $this->altura_m);
        $stmt->bindParam(":condicion_arbol", $this->condicion_arbol);
        $stmt->bindParam(":estado_sincronizacion", $this->estado_sincronizacion);
        $stmt->bindParam(":usuario_id", $this->usuario_id);

        if ($stmt->execute()) {
            $this->id = $this->conn->lastInsertId();
            return true;
        }

        return false;
    }

    // Crear múltiples registros en lote (para sincronización)
    public function createBatch($records) {
        $this->conn->beginTransaction();
        
        try {
            $query = "INSERT INTO " . $this->table_name . " 
                      (rodal_id, numero_parcela, latitud, longitud, especie_id, dap_cm, 
                       altura_m, condicion_arbol, estado_sincronizacion, usuario_id, fecha_captura) 
                      VALUES (:rodal_id, :numero_parcela, :latitud, :longitud, :especie_id, 
                              :dap_cm, :altura_m, :condicion_arbol, :estado_sincronizacion, :usuario_id, :fecha_captura)";

            $stmt = $this->conn->prepare($query);
            $successCount = 0;
            $errors = [];

            foreach ($records as $index => $record) {
                // Validar cada registro
                $validation = $this->validateRecord($record);
                if (!empty($validation)) {
                    $errors[] = "Registro " . ($index + 1) . ": " . implode(", ", $validation);
                    continue;
                }

                // Bind de parámetros para cada registro
                $stmt->bindParam(":rodal_id", $record['rodal_id']);
                $stmt->bindParam(":numero_parcela", $record['numero_parcela']);
                $stmt->bindParam(":latitud", $record['latitud']);
                $stmt->bindParam(":longitud", $record['longitud']);
                $stmt->bindParam(":especie_id", $record['especie_id']);
                $stmt->bindParam(":dap_cm", $record['dap_cm']);
                $stmt->bindParam(":altura_m", $record['altura_m']);
                $stmt->bindParam(":condicion_arbol", $record['condicion_arbol']);
                $stmt->bindParam(":estado_sincronizacion", $record['estado_sincronizacion']);
                $stmt->bindParam(":usuario_id", $record['usuario_id']);
                $stmt->bindParam(":fecha_captura", $record['fecha_captura']);

                if ($stmt->execute()) {
                    $successCount++;
                } else {
                    $errors[] = "Error al insertar registro " . ($index + 1);
                }
            }

            if (empty($errors)) {
                $this->conn->commit();
                return ['success' => true, 'inserted' => $successCount];
            } else {
                $this->conn->rollback();
                return ['success' => false, 'errors' => $errors, 'inserted' => 0];
            }

        } catch (Exception $e) {
            $this->conn->rollback();
            return ['success' => false, 'errors' => [$e->getMessage()], 'inserted' => 0];
        }
    }

    // Obtener registros de campo
    public function read() {
        $query = "SELECT dc.*, r.nombre_rodal, p.nombre_proyecto, e.nombre_cientifico, e.nombre_comun, u.nombre as usuario_nombre
                  FROM " . $this->table_name . " dc
                  LEFT JOIN rodales r ON dc.rodal_id = r.id
                  LEFT JOIN proyectos p ON r.proyecto_id = p.id
                  LEFT JOIN especies e ON dc.especie_id = e.id
                  LEFT JOIN usuarios u ON dc.usuario_id = u.id
                  ORDER BY dc.fecha_captura DESC";

        $stmt = $this->conn->prepare($query);
        $stmt->execute();

        return $stmt;
    }

    // Obtener registros por rodal
    public function readByRodal($rodalId) {
        $query = "SELECT dc.*, e.nombre_cientifico, e.nombre_comun, u.nombre as usuario_nombre
                  FROM " . $this->table_name . " dc
                  LEFT JOIN especies e ON dc.especie_id = e.id
                  LEFT JOIN usuarios u ON dc.usuario_id = u.id
                  WHERE dc.rodal_id = :rodal_id
                  ORDER BY dc.numero_parcela ASC, dc.fecha_captura ASC";

        $stmt = $this->conn->prepare($query);
        $stmt->bindParam(":rodal_id", $rodalId);
        $stmt->execute();

        return $stmt;
    }

    // Obtener registros por rodal como array (para cálculos)
    public function getByRodalId($rodalId) {
        $query = "SELECT dc.*, e.nombre_cientifico, e.nombre_comun, u.nombre as usuario_nombre
                  FROM " . $this->table_name . " dc
                  LEFT JOIN especies e ON dc.especie_id = e.id
                  LEFT JOIN usuarios u ON dc.usuario_id = u.id
                  WHERE dc.rodal_id = :rodal_id
                  ORDER BY dc.numero_parcela ASC, dc.fecha_captura ASC";

        $stmt = $this->conn->prepare($query);
        $stmt->bindParam(":rodal_id", $rodalId);
        $stmt->execute();

        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    // Obtener registros por rodal con información completa de especies (para reportes)
    public function getByRodalIdWithSpecies($rodalId) {
        $query = "SELECT dc.*, 
                         e.nombre_cientifico as especie_cientifico,
                         e.nombre_comun as especie_nombre,
                         u.nombre as usuario_nombre
                  FROM " . $this->table_name . " dc
                  LEFT JOIN especies e ON dc.especie_id = e.id
                  LEFT JOIN usuarios u ON dc.usuario_id = u.id
                  WHERE dc.rodal_id = :rodal_id
                  ORDER BY dc.numero_parcela ASC, dc.fecha_captura ASC";

        $stmt = $this->conn->prepare($query);
        $stmt->bindParam(":rodal_id", $rodalId);
        $stmt->execute();

        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    // Obtener registros pendientes de sincronización
    public function getPendingSync($userId = null) {
        $query = "SELECT dc.*, r.nombre_rodal, p.nombre_proyecto, e.nombre_cientifico, e.nombre_comun
                  FROM " . $this->table_name . " dc
                  LEFT JOIN rodales r ON dc.rodal_id = r.id
                  LEFT JOIN proyectos p ON r.proyecto_id = p.id
                  LEFT JOIN especies e ON dc.especie_id = e.id
                  WHERE dc.estado_sincronizacion = 'Pendiente'";

        if ($userId) {
            $query .= " AND dc.usuario_id = :usuario_id";
        }

        $query .= " ORDER BY dc.fecha_captura ASC";

        $stmt = $this->conn->prepare($query);
        
        if ($userId) {
            $stmt->bindParam(":usuario_id", $userId);
        }
        
        $stmt->execute();

        return $stmt;
    }

    // Buscar registro por ID
    public function findById($id) {
        $query = "SELECT dc.*, r.nombre_rodal, p.nombre_proyecto, e.nombre_cientifico, e.nombre_comun, u.nombre as usuario_nombre
                  FROM " . $this->table_name . " dc
                  LEFT JOIN rodales r ON dc.rodal_id = r.id
                  LEFT JOIN proyectos p ON r.proyecto_id = p.id
                  LEFT JOIN especies e ON dc.especie_id = e.id
                  LEFT JOIN usuarios u ON dc.usuario_id = u.id
                  WHERE dc.id = :id 
                  LIMIT 1";

        $stmt = $this->conn->prepare($query);
        $stmt->bindParam(":id", $id);
        $stmt->execute();

        if ($stmt->rowCount() > 0) {
            $row = $stmt->fetch(PDO::FETCH_ASSOC);
            
            $this->id = $row['id'];
            $this->rodal_id = $row['rodal_id'];
            $this->numero_parcela = $row['numero_parcela'];
            $this->fecha_captura = $row['fecha_captura'];
            $this->latitud = $row['latitud'];
            $this->longitud = $row['longitud'];
            $this->especie_id = $row['especie_id'];
            $this->dap_cm = $row['dap_cm'];
            $this->altura_m = $row['altura_m'];
            $this->condicion_arbol = $row['condicion_arbol'];
            $this->estado_sincronizacion = $row['estado_sincronizacion'];
            $this->usuario_id = $row['usuario_id'];
            $this->fecha_sincronizacion = $row['fecha_sincronizacion'];
            
            return true;
        }

        return false;
    }

    // Actualizar registro
    public function update() {
        $query = "UPDATE " . $this->table_name . " 
                  SET numero_parcela = :numero_parcela, latitud = :latitud, longitud = :longitud,
                      especie_id = :especie_id, dap_cm = :dap_cm, altura_m = :altura_m,
                      condicion_arbol = :condicion_arbol
                  WHERE id = :id";

        $stmt = $this->conn->prepare($query);

        // Sanitizar y validar datos
        $this->numero_parcela = intval($this->numero_parcela);
        $this->latitud = floatval($this->latitud);
        $this->longitud = floatval($this->longitud);
        $this->especie_id = intval($this->especie_id);
        $this->dap_cm = floatval($this->dap_cm);
        $this->altura_m = floatval($this->altura_m);
        $this->condicion_arbol = htmlspecialchars(strip_tags($this->condicion_arbol));

        // Bind de parámetros
        $stmt->bindParam(":numero_parcela", $this->numero_parcela);
        $stmt->bindParam(":latitud", $this->latitud);
        $stmt->bindParam(":longitud", $this->longitud);
        $stmt->bindParam(":especie_id", $this->especie_id);
        $stmt->bindParam(":dap_cm", $this->dap_cm);
        $stmt->bindParam(":altura_m", $this->altura_m);
        $stmt->bindParam(":condicion_arbol", $this->condicion_arbol);
        $stmt->bindParam(":id", $this->id);

        return $stmt->execute();
    }

    // Marcar como sincronizado
    public function markAsSynced($ids) {
        if (empty($ids)) {
            return false;
        }

        $placeholders = str_repeat('?,', count($ids) - 1) . '?';
        $query = "UPDATE " . $this->table_name . " 
                  SET estado_sincronizacion = 'Sincronizado', fecha_sincronizacion = CURRENT_TIMESTAMP 
                  WHERE id IN ($placeholders)";

        $stmt = $this->conn->prepare($query);
        return $stmt->execute($ids);
    }

    // Eliminar registro
    public function delete() {
        $query = "DELETE FROM " . $this->table_name . " WHERE id = :id";
        $stmt = $this->conn->prepare($query);
        $stmt->bindParam(":id", $this->id);

        return $stmt->execute();
    }

    // Validar datos forestales
    public function validate() {
        return $this->validateRecord([
            'rodal_id' => $this->rodal_id,
            'numero_parcela' => $this->numero_parcela,
            'latitud' => $this->latitud,
            'longitud' => $this->longitud,
            'especie_id' => $this->especie_id,
            'dap_cm' => $this->dap_cm,
            'altura_m' => $this->altura_m,
            'condicion_arbol' => $this->condicion_arbol,
            'usuario_id' => $this->usuario_id
        ]);
    }

    // Validar un registro individual
    private function validateRecord($record) {
        $errors = [];

        // Validar rodal_id
        if (empty($record['rodal_id'])) {
            $errors[] = "El ID del rodal es requerido";
        } else {
            // Verificar que el rodal existe
            $checkQuery = "SELECT id FROM rodales WHERE id = :rodal_id";
            $checkStmt = $this->conn->prepare($checkQuery);
            $checkStmt->bindParam(":rodal_id", $record['rodal_id']);
            $checkStmt->execute();
            
            if ($checkStmt->rowCount() === 0) {
                $errors[] = "El rodal especificado no existe";
            }
        }

        // Validar número de parcela
        if (empty($record['numero_parcela']) || $record['numero_parcela'] <= 0) {
            $errors[] = "El número de parcela debe ser mayor a 0";
        } elseif ($record['numero_parcela'] > 9999) {
            $errors[] = "El número de parcela no puede exceder 9999";
        }

        // Validar coordenadas GPS
        if (empty($record['latitud']) || !is_numeric($record['latitud'])) {
            $errors[] = "La latitud es requerida y debe ser numérica";
        } elseif ($record['latitud'] < -90 || $record['latitud'] > 90) {
            $errors[] = "La latitud debe estar entre -90 y 90 grados";
        }

        if (empty($record['longitud']) || !is_numeric($record['longitud'])) {
            $errors[] = "La longitud es requerida y debe ser numérica";
        } elseif ($record['longitud'] < -180 || $record['longitud'] > 180) {
            $errors[] = "La longitud debe estar entre -180 y 180 grados";
        }

        // Validar coordenadas específicas para Guatemala
        if (!empty($record['latitud']) && !empty($record['longitud'])) {
            if ($record['latitud'] < 13.5 || $record['latitud'] > 18.0 || 
                $record['longitud'] < -93.0 || $record['longitud'] > -88.0) {
                $errors[] = "Las coordenadas parecen estar fuera del territorio de Guatemala";
            }
        }

        // Validar especie
        if (empty($record['especie_id'])) {
            $errors[] = "La especie es requerida";
        } else {
            // Verificar que la especie existe y está activa
            $checkQuery = "SELECT id FROM especies WHERE id = :especie_id AND activa = 1";
            $checkStmt = $this->conn->prepare($checkQuery);
            $checkStmt->bindParam(":especie_id", $record['especie_id']);
            $checkStmt->execute();
            
            if ($checkStmt->rowCount() === 0) {
                $errors[] = "La especie especificada no existe o no está activa";
            }
        }

        // Validar DAP (Diámetro a la Altura del Pecho)
        if (empty($record['dap_cm']) || $record['dap_cm'] <= 0) {
            $errors[] = "El DAP debe ser mayor a 0 cm";
        } elseif ($record['dap_cm'] < 5) {
            $errors[] = "El DAP es muy pequeño (< 5 cm), verifique la medición";
        } elseif ($record['dap_cm'] > 300) {
            $errors[] = "El DAP es excesivamente grande (> 300 cm), verifique la medición";
        } elseif (!is_numeric($record['dap_cm'])) {
            $errors[] = "El DAP debe ser un valor numérico";
        }

        // Validar altura
        if (empty($record['altura_m']) || $record['altura_m'] <= 0) {
            $errors[] = "La altura debe ser mayor a 0 metros";
        } elseif ($record['altura_m'] < 0.5) {
            $errors[] = "La altura es muy pequeña (< 0.5 m), verifique la medición";
        } elseif ($record['altura_m'] > 80) {
            $errors[] = "La altura es excesivamente grande (> 80 m), verifique la medición";
        } elseif (!is_numeric($record['altura_m'])) {
            $errors[] = "La altura debe ser un valor numérico";
        }

        // Validar condición del árbol
        $condicionesValidas = ['Sano', 'Bifurcado', 'Plagado', 'Muerto en Pie'];
        if (empty($record['condicion_arbol'])) {
            $errors[] = "La condición del árbol es requerida";
        } elseif (!in_array($record['condicion_arbol'], $condicionesValidas)) {
            $errors[] = "La condición del árbol debe ser: " . implode(', ', $condicionesValidas);
        }

        // Validar usuario_id
        if (empty($record['usuario_id'])) {
            $errors[] = "El ID del usuario es requerido";
        }

        return $errors;
    }

    // Obtener alertas de valores atípicos
    public function getOutlierAlerts($record) {
        $alerts = [];

        // Alertas para DAP
        if ($record['dap_cm'] > 200) {
            $alerts[] = [
                'type' => 'warning',
                'field' => 'dap_cm',
                'message' => 'DAP muy grande (' . $record['dap_cm'] . ' cm). ¿Está seguro de la medición?'
            ];
        }

        if ($record['dap_cm'] < 10) {
            $alerts[] = [
                'type' => 'info',
                'field' => 'dap_cm',
                'message' => 'DAP pequeño (' . $record['dap_cm'] . ' cm). Verifique que el árbol califique para inventario.'
            ];
        }

        // Alertas para altura
        if ($record['altura_m'] > 50) {
            $alerts[] = [
                'type' => 'warning',
                'field' => 'altura_m',
                'message' => 'Altura muy grande (' . $record['altura_m'] . ' m). ¿Está seguro de la medición?'
            ];
        }

        if ($record['altura_m'] < 2) {
            $alerts[] = [
                'type' => 'info',
                'field' => 'altura_m',
                'message' => 'Altura pequeña (' . $record['altura_m'] . ' m). Verifique que el árbol califique para inventario.'
            ];
        }

        // Alerta para relación DAP/Altura inusual
        if ($record['dap_cm'] > 0 && $record['altura_m'] > 0) {
            $ratio = $record['altura_m'] / ($record['dap_cm'] / 100); // altura en metros / DAP en metros
            
            if ($ratio < 0.3) {
                $alerts[] = [
                    'type' => 'warning',
                    'field' => 'ratio',
                    'message' => 'Relación altura/DAP inusual. Árbol muy bajo para su diámetro.'
                ];
            } elseif ($ratio > 2.5) {
                $alerts[] = [
                    'type' => 'warning',
                    'field' => 'ratio',
                    'message' => 'Relación altura/DAP inusual. Árbol muy alto para su diámetro.'
                ];
            }
        }

        return $alerts;
    }

    // Obtener estadísticas de calidad de datos
    public function getDataQualityStats($rodalId = null) {
        $whereClause = $rodalId ? "WHERE rodal_id = :rodal_id" : "";
        
        $query = "SELECT 
                    COUNT(*) as total_registros,
                    COUNT(CASE WHEN dap_cm > 200 THEN 1 END) as dap_outliers,
                    COUNT(CASE WHEN altura_m > 50 THEN 1 END) as altura_outliers,
                    COUNT(CASE WHEN dap_cm < 10 THEN 1 END) as dap_pequenos,
                    COUNT(CASE WHEN altura_m < 2 THEN 1 END) as altura_pequenos,
                    AVG(dap_cm) as dap_promedio,
                    AVG(altura_m) as altura_promedio,
                    STDDEV(dap_cm) as dap_desviacion,
                    STDDEV(altura_m) as altura_desviacion
                  FROM " . $this->table_name . " " . $whereClause;

        $stmt = $this->conn->prepare($query);
        
        if ($rodalId) {
            $stmt->bindParam(":rodal_id", $rodalId);
        }
        
        $stmt->execute();

        return $stmt->fetch(PDO::FETCH_ASSOC);
    }

    // Exportar datos para CSV
    public function exportToCSV($rodalId) {
        $query = "SELECT 
                    r.nombre_rodal,
                    p.nombre_proyecto,
                    dc.numero_parcela,
                    dc.fecha_captura,
                    dc.latitud,
                    dc.longitud,
                    e.nombre_cientifico,
                    e.nombre_comun,
                    dc.dap_cm,
                    dc.altura_m,
                    dc.condicion_arbol,
                    u.nombre as medido_por
                  FROM " . $this->table_name . " dc
                  LEFT JOIN rodales r ON dc.rodal_id = r.id
                  LEFT JOIN proyectos p ON r.proyecto_id = p.id
                  LEFT JOIN especies e ON dc.especie_id = e.id
                  LEFT JOIN usuarios u ON dc.usuario_id = u.id
                  WHERE dc.rodal_id = :rodal_id
                  ORDER BY dc.numero_parcela ASC, dc.fecha_captura ASC";

        $stmt = $this->conn->prepare($query);
        $stmt->bindParam(":rodal_id", $rodalId);
        $stmt->execute();

        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    // Obtener registros duplicados potenciales
    public function findPotentialDuplicates($rodalId) {
        $query = "SELECT 
                    numero_parcela,
                    latitud,
                    longitud,
                    especie_id,
                    dap_cm,
                    altura_m,
                    COUNT(*) as duplicates,
                    GROUP_CONCAT(id) as ids
                  FROM " . $this->table_name . "
                  WHERE rodal_id = :rodal_id
                  GROUP BY numero_parcela, latitud, longitud, especie_id, dap_cm, altura_m
                  HAVING COUNT(*) > 1";

        $stmt = $this->conn->prepare($query);
        $stmt->bindParam(":rodal_id", $rodalId);
        $stmt->execute();

        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
}
?>