<?php
/**
 * Modelo Letra
 * Gestiona las letras individuales de cambio
 */
class Letra
{
    private PDO $db;

    public function __construct()
    {
        $this->db = Conexion::getConexion();
    }

    /**
     * Obtener todas las letras con info de empresa y grupo
     */
    public function getAll(string $filtroEstado = '', int $empresaId = 0, string $fechaDesde = '', string $fechaHasta = '', string $fechaEmisionFactura = '', string $numeroLetra = ''): array
    {
        $sql = "SELECT l.*, e.razon_social, g.documento_sunat, g.serie, g.fecha_emision_factura,
                DATEDIFF(l.fecha_vencimiento, CURDATE()) as dias_para_vencer,
                DATEDIFF(l.fecha_pago, CURDATE()) as dias_para_pagar
                FROM letras l
                INNER JOIN empresas e ON l.empresa_id = e.id
                INNER JOIN grupos_letras g ON l.grupo_id = g.id
                WHERE 1=1";
        
        $params = [];

        if (!empty($filtroEstado)) {
            $sql .= " AND l.estado = :estado";
            $params[':estado'] = $filtroEstado;
        }

        if ($empresaId > 0) {
            $sql .= " AND l.empresa_id = :empresa_id";
            $params[':empresa_id'] = $empresaId;
        }

        if (!empty($fechaDesde)) {
            $sql .= " AND l.fecha_vencimiento >= :fecha_desde";
            $params[':fecha_desde'] = $fechaDesde;
        }

        if (!empty($fechaHasta)) {
            $sql .= " AND l.fecha_vencimiento <= :fecha_hasta";
            $params[':fecha_hasta'] = $fechaHasta;
        }

        if (!empty($fechaEmisionFactura)) {
            $sql .= " AND g.fecha_emision_factura = :fecha_emision_factura";
            $params[':fecha_emision_factura'] = $fechaEmisionFactura;
        }

        if (!empty($numeroLetra)) {
            $sql .= " AND l.numero_letra LIKE :numero_letra";
            $params[':numero_letra'] = '%' . $numeroLetra . '%';
        }

        $sql .= " ORDER BY l.fecha_vencimiento ASC";

        $stmt = $this->db->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetchAll();
    }

    /**
     * Obtener letra por ID
     */
    public function getById(int $id): ?array
    {
        $sql = "SELECT l.*, e.razon_social, g.documento_sunat, g.serie,
                DATEDIFF(l.fecha_vencimiento, CURDATE()) as dias_para_vencer,
                DATEDIFF(l.fecha_pago, CURDATE()) as dias_para_pagar
                FROM letras l
                INNER JOIN empresas e ON l.empresa_id = e.id
                INNER JOIN grupos_letras g ON l.grupo_id = g.id
                WHERE l.id = :id";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([':id' => $id]);
        $result = $stmt->fetch();
        return $result ?: null;
    }

    /**
     * Crear una nueva letra
     */
    public function crear(array $data): int
    {
        $sql = "INSERT INTO letras (grupo_id, empresa_id, numero_letra, numero_en_grupo, renovacion, tipo_letra, moneda, fecha_emision, plazo_dias, fecha_vencimiento, importe, banco, estado, referencia_unica, observaciones)
                VALUES (:grupo_id, :empresa_id, :numero_letra, :numero_en_grupo, :renovacion, :tipo_letra, :moneda, :fecha_emision, :plazo_dias, :fecha_vencimiento, :importe, :banco, :estado, :referencia_unica, :observaciones)";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([
            ':grupo_id'          => $data['grupo_id'],
            ':empresa_id'        => $data['empresa_id'],
            ':numero_letra'      => $data['numero_letra'],
            ':numero_en_grupo'   => $data['numero_en_grupo'] ?? 1,
            ':renovacion'        => $data['renovacion'] ?? 0,
            ':tipo_letra'        => $data['tipo_letra'] ?? 'ORI',
            ':moneda'            => $data['moneda'] ?? 'USD',
            ':fecha_emision'     => $data['fecha_emision'],
            ':plazo_dias'        => $data['plazo_dias'],
            ':fecha_vencimiento' => $data['fecha_vencimiento'],
            ':importe'           => $data['importe'],
            ':banco'             => $data['banco'] ?? null,
            ':estado'            => $data['estado'] ?? 'pendiente',
            ':referencia_unica'  => $data['referencia_unica'] ?? null,
            ':observaciones'     => $data['observaciones'] ?? null
        ]);
        return (int)$this->db->lastInsertId();
    }

    /**
     * Procesar renovación: actualiza original e inserta nueva en transacción
     */
    public function renovarLetra(int $idOriginal, array $datosNuevaLetra, string $obsOriginal): bool
    {
        try {
            $this->db->beginTransaction();
            
            // Actualizar original
            $sql = "UPDATE letras SET estado = 'renovada', observaciones = :obs WHERE id = :id";
            $stmt = $this->db->prepare($sql);
            $stmt->execute([':obs' => $obsOriginal, ':id' => $idOriginal]);
            
            // Insertar nueva
            $this->crear($datosNuevaLetra);
            
            $this->db->commit();
            return true;
        } catch (\Exception $e) {
            $this->db->rollBack();
            throw $e;
        }
    }

    /**
     * Actualizar una letra
     */
    public function update(int $id, array $data): bool
    {
        $sql = "UPDATE letras SET 
                numero_letra = :numero_letra,
                renovacion = :renovacion,
                tipo_letra = :tipo_letra,
                moneda = :moneda,
                fecha_emision = :fecha_emision,
                plazo_dias = :plazo_dias,
                fecha_vencimiento = :fecha_vencimiento,
                importe = :importe,
                banco = :banco,
                estado = :estado,
                referencia_unica = :referencia_unica,
                observaciones = :observaciones
                WHERE id = :id";
        
        $stmt = $this->db->prepare($sql);
        return $stmt->execute([
            ':numero_letra'      => $data['numero_letra'],
            ':renovacion'        => $data['renovacion'] ?? 0,
            ':tipo_letra'        => $data['tipo_letra'] ?? 'ORI',
            ':moneda'            => $data['moneda'] ?? 'USD',
            ':fecha_emision'     => $data['fecha_emision'],
            ':plazo_dias'        => $data['plazo_dias'] ?? 30,
            ':fecha_vencimiento' => $data['fecha_vencimiento'],
            ':importe'           => $data['importe'],
            ':banco'             => $data['banco'] ?? null,
            ':estado'            => $data['estado'] ?? 'pendiente',
            ':referencia_unica'  => $data['referencia_unica'] ?? null,
            ':observaciones'     => $data['observaciones'] ?? null,
            ':id'                => $id,
        ]);
    }

    /**
     * Cambiar estado de una letra
     */
    public function cambiarEstado(int $id, string $estado): bool
    {
        $sql = "UPDATE letras SET estado = :estado WHERE id = :id";
        $stmt = $this->db->prepare($sql);
        return $stmt->execute([':estado' => $estado, ':id' => $id]);
    }

    /**
     * Marcar múltiples letras como pagadas
     */
    public function marcarPagadasMasivo(array $ids): bool
    {
        if (empty($ids)) return false;
        
        // Prepare IN clause placeholders
        $placeholders = implode(',', array_fill(0, count($ids), '?'));
        
        $sql = "UPDATE letras SET estado = 'pagada' WHERE id IN ($placeholders)";
        $stmt = $this->db->prepare($sql);
        
        return $stmt->execute($ids);
    }

    /**
     * Eliminar letra
     */
    public function delete(int $id): bool
    {
        $sql = "DELETE FROM letras WHERE id = :id";
        $stmt = $this->db->prepare($sql);
        return $stmt->execute([':id' => $id]);
    }

    /**
     * Obtener letras que están por vencer o dentro del período de pago
     * Para las alertas Toast
     */
    public function getAlertasVencimiento(): array
    {
        $sql = "SELECT l.*, e.razon_social,
                DATEDIFF(l.fecha_vencimiento, CURDATE()) as dias_para_vencer,
                DATEDIFF(l.fecha_pago, CURDATE()) as dias_para_pagar
                FROM letras l
                INNER JOIN empresas e ON l.empresa_id = e.id
                WHERE l.estado = 'pendiente'
                AND l.fecha_pago >= CURDATE()
                AND l.fecha_vencimiento <= DATE_ADD(CURDATE(), INTERVAL 8 DAY)
                ORDER BY l.fecha_vencimiento ASC";
        $stmt = $this->db->query($sql);
        return $stmt->fetchAll();
    }

    /**
     * Obtener letras que excedieron el plazo de pago (fecha_pago < hoy)
     */
    public function getLetrasExcedidas(): array
    {
        $sql = "SELECT l.*, e.razon_social,
                DATEDIFF(CURDATE(), l.fecha_pago) as dias_excedidos
                FROM letras l
                INNER JOIN empresas e ON l.empresa_id = e.id
                WHERE l.estado = 'pendiente'
                AND l.fecha_pago < CURDATE()
                ORDER BY l.fecha_vencimiento ASC";
        $stmt = $this->db->query($sql);
        return $stmt->fetchAll();
    }

    // ============================================================
    // ESTADÍSTICAS PARA EL DASHBOARD
    // ============================================================

    /**
     * Conteo total de letras
     */
    public function countTotal(): int
    {
        $stmt = $this->db->query("SELECT COUNT(*) as total FROM letras");
        return (int)$stmt->fetch()['total'];
    }

    /**
     * Conteo por estado
     */
    public function countByEstado(string $estado): int
    {
        $stmt = $this->db->prepare("SELECT COUNT(*) as total FROM letras WHERE estado = :estado");
        $stmt->execute([':estado' => $estado]);
        return (int)$stmt->fetch()['total'];
    }

    /**
     * Letras pendientes que vencen en los próximos N días
     */
    public function countPorVencer(int $dias = 8): int
    {
        $sql = "SELECT COUNT(*) as total FROM letras 
                WHERE estado = 'pendiente' 
                AND fecha_vencimiento BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL :dias DAY)";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([':dias' => $dias]);
        return (int)$stmt->fetch()['total'];
    }

    /**
     * Letras vencidas (fecha_vencimiento < hoy y estado pendiente)
     */
    public function countVencidas(): int
    {
        $sql = "SELECT COUNT(*) as total FROM letras 
                WHERE estado = 'pendiente' 
                AND fecha_vencimiento < CURDATE()";
        $stmt = $this->db->query($sql);
        return (int)$stmt->fetch()['total'];
    }

    /**
     * Monto total por estado en USD
     */
    public function montoTotalByEstado(string $estado): float
    {
        $stmt = $this->db->prepare("SELECT COALESCE(SUM(importe), 0) as total FROM letras WHERE estado = :estado");
        $stmt->execute([':estado' => $estado]);
        return (float)$stmt->fetch()['total'];
    }

    /**
     * Monto total pendiente USD
     */
    public function montoTotalPendiente(): float
    {
        $stmt = $this->db->query("SELECT COALESCE(SUM(importe), 0) as total FROM letras WHERE estado = 'pendiente'");
        return (float)$stmt->fetch()['total'];
    }

    /**
     * Montos mensuales para gráfico de barras
     */
    public function montosMensuales(int $year = 0): array
    {
        if ($year === 0) $year = (int)date('Y');

        $sql = "SELECT MONTH(fecha_vencimiento) as mes, 
                SUM(importe) as total
                FROM letras 
                WHERE YEAR(fecha_vencimiento) = :year
                GROUP BY MONTH(fecha_vencimiento)
                ORDER BY mes";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([':year' => $year]);
        $results = $stmt->fetchAll();

        // Llenar los 12 meses
        $meses = array_fill(1, 12, 0);
        foreach ($results as $row) {
            $meses[(int)$row['mes']] = (float)$row['total'];
        }
        return $meses;
    }

    /**
     * Distribución por estado para gráfico de pastel
     */
    public function distribucionEstados(): array
    {
        $sql = "SELECT estado, COUNT(*) as cantidad, SUM(importe) as monto
                FROM letras 
                GROUP BY estado";
        $stmt = $this->db->query($sql);
        return $stmt->fetchAll();
    }
}
