<?php
namespace Modules\Locadora\Controllers;

use Gestoreasy\Core\Http\Request;
use Gestoreasy\Core\Http\Response;
use Gestoreasy\Core\Tenant\ConnectionManager;
use Gestoreasy\Core\Audit\AuditLogger;
use Gestoreasy\Core\View\View;
use PDO;
use Exception;

class ContratosController {
    private PDO $pdo;
    
    public function __construct() {
        $this->pdo = ConnectionManager::forTenant();
    }
    
    // ==== Views ====
    public function viewIndex(Request $r): Response {
        return View::renderWithLayout('locadora/contratos/index', ['title' => 'Contratos de Locação']);
    }
    
    public function viewCreate(Request $r): Response {
        return View::renderWithLayout('locadora/contratos/create', ['title' => 'Novo Contrato']);
    }
    
    public function viewShow(Request $r): Response {
        $id = $r->params['id'] ?? 0;
        return View::renderWithLayout('locadora/contratos/show', ['title' => 'Detalhes do Contrato', 'id' => $id]);
    }
    
    // ==== API ====
    public function list(Request $r): Response {
        try {
            $page = max(1, (int)($r->query['page'] ?? 1));
            $perPage = min(100, max(1, (int)($r->query['per_page'] ?? 20)));
            $offset = ($page - 1) * $perPage;
            
            $where = [];
            $params = [];
            
            if (!empty($r->query['status'])) {
                $where[] = 'c.status = ?';
                $params[] = $r->query['status'];
            }
            
            if (!empty($r->query['cliente_id'])) {
                $where[] = 'c.cliente_id = ?';
                $params[] = (int)$r->query['cliente_id'];
            }
            
            if (!empty($r->query['veiculo_id'])) {
                $where[] = 'c.veiculo_id = ?';
                $params[] = (int)$r->query['veiculo_id'];
            }
            
            $whereSql = !empty($where) ? 'WHERE ' . implode(' AND ', $where) : '';
            
            $countStmt = $this->pdo->prepare("SELECT COUNT(*) FROM locadora_contratos c $whereSql");
            $countStmt->execute($params);
            $total = (int)$countStmt->fetchColumn();
            
            $stmt = $this->pdo->prepare("
                SELECT c.*, 
                       cl.nome as cliente_nome, cl.email as cliente_email, cl.telefone as cliente_telefone,
                       v.placa as veiculo_placa, v.marca as veiculo_marca, v.modelo as veiculo_modelo
                FROM locadora_contratos c
                LEFT JOIN clients cl ON c.cliente_id = cl.id
                LEFT JOIN locadora_frota v ON c.veiculo_id = v.id
                $whereSql
                ORDER BY c.data_inicio DESC
                LIMIT $perPage OFFSET $offset
            ");
            $stmt->execute($params);
            $contratos = $stmt->fetchAll(PDO::FETCH_ASSOC);
            
            return Response::json([
                'data' => $contratos,
                'pagination' => [
                    'page' => $page,
                    'per_page' => $perPage,
                    'total' => $total,
                    'pages' => (int)ceil($total / $perPage)
                ]
            ]);
        } catch (Exception $e) {
            return Response::json(['error' => $e->getMessage()], 500);
        }
    }
    
    public function getById(Request $r): Response {
        try {
            $id = (int)($r->params['id'] ?? 0);
            if ($id <= 0) {
                return Response::json(['error' => 'ID inválido'], 400);
            }
            
            $stmt = $this->pdo->prepare("
                SELECT c.*, 
                       cl.nome as cliente_nome, cl.email as cliente_email, cl.telefone as cliente_telefone,
                       v.placa as veiculo_placa, v.marca as veiculo_marca, v.modelo as veiculo_modelo, v.km_atual as veiculo_km
                FROM locadora_contratos c
                LEFT JOIN clients cl ON c.cliente_id = cl.id
                LEFT JOIN locadora_frota v ON c.veiculo_id = v.id
                WHERE c.id = ?
            ");
            $stmt->execute([$id]);
            $contrato = $stmt->fetch(PDO::FETCH_ASSOC);
            
            if (!$contrato) {
                return Response::json(['error' => 'Contrato não encontrado'], 404);
            }
            
            return Response::json(['data' => $contrato]);
        } catch (Exception $e) {
            return Response::json(['error' => $e->getMessage()], 500);
        }
    }
    
    public function create(Request $r): Response {
        try {
            $data = $r->body;
            
            // Gerar número do contrato
            $numero = $this->gerarNumeroContrato();
            
            // Calcular valores
            $dataInicio = $data['data_inicio'] ?? date('Y-m-d');
            $dataFim = $data['data_fim'] ?? date('Y-m-d');
            $quantidadeDias = max(1, (int)((strtotime($dataFim) - strtotime($dataInicio)) / 86400) + 1);
            
            // Buscar valor da diária do veículo
            $veiculoStmt = $this->pdo->prepare("SELECT valor_diaria, km_atual, status FROM locadora_frota WHERE id = ?");
            $veiculoStmt->execute([(int)($data['veiculo_id'] ?? 0)]);
            $veiculo = $veiculoStmt->fetch(PDO::FETCH_ASSOC);
            
            if (!$veiculo) {
                return Response::json(['error' => 'Veículo não encontrado'], 404);
            }
            
            if ($veiculo['status'] !== 'disponivel') {
                return Response::json(['error' => 'Veículo não está disponível'], 400);
            }
            
            $valorDiaria = (float)($data['valor_diaria'] ?? $veiculo['valor_diaria']);
            $valorTotal = $valorDiaria * $quantidadeDias;
            $kmSaida = (float)($veiculo['km_atual']);
            
            $this->pdo->beginTransaction();
            
            // Criar contrato
            $stmt = $this->pdo->prepare("
                INSERT INTO locadora_contratos (
                    numero, cliente_id, veiculo_id, data_inicio, data_fim,
                    km_saida, km_limite, valor_diaria, quantidade_dias, valor_total,
                    status, forma_pagamento, observacoes
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ");
            
            $stmt->execute([
                $numero,
                (int)($data['cliente_id'] ?? 0),
                (int)($data['veiculo_id'] ?? 0),
                $dataInicio,
                $dataFim,
                $kmSaida,
                !empty($data['km_limite']) ? (float)$data['km_limite'] : null,
                $valorDiaria,
                $quantidadeDias,
                $valorTotal,
                'aberto',
                $data['forma_pagamento'] ?? null,
                $data['observacoes'] ?? null
            ]);
            
            $contratoId = (int)$this->pdo->lastInsertId();
            
            // Atualizar status do veículo
            $updateVeiculoStmt = $this->pdo->prepare("UPDATE locadora_frota SET status = 'locado', updated_at = CURRENT_TIMESTAMP WHERE id = ?");
            $updateVeiculoStmt->execute([(int)($data['veiculo_id'] ?? 0)]);
            
            // Registrar KM de saída
            $kmStmt = $this->pdo->prepare("
                INSERT INTO locadora_km_historico (veiculo_id, contrato_id, km_anterior, km_atual, km_percorrido, tipo)
                VALUES (?, ?, ?, ?, 0, 'saida')
            ");
            $kmStmt->execute([(int)($data['veiculo_id'] ?? 0), $contratoId, $kmSaida, $kmSaida]);
            
            $this->pdo->commit();
            AuditLogger::logCreate('locadora_contratos', $contratoId, $data);
            
            return Response::json(['data' => ['id' => $contratoId, 'numero' => $numero]], 201);
        } catch (Exception $e) {
            $this->pdo->rollBack();
            return Response::json(['error' => $e->getMessage()], 500);
        }
    }
    
    public function update(Request $r): Response {
        try {
            $id = (int)($r->params['id'] ?? 0);
            if ($id <= 0) {
                return Response::json(['error' => 'ID inválido'], 400);
            }
            
            $data = $r->body;
            
            $updateFields = [];
            $params = [];
            
            $fields = [
                'data_inicio', 'data_fim', 'data_devolucao', 'km_retorno', 'km_limite',
                'valor_diaria', 'quantidade_dias', 'valor_total', 'valor_adicional', 'valor_final',
                'status', 'forma_pagamento', 'observacoes'
            ];
            
            foreach ($fields as $field) {
                if (isset($data[$field])) {
                    $updateFields[] = "$field = ?";
                    if (in_array($field, ['km_retorno', 'km_limite', 'valor_diaria', 'quantidade_dias', 'valor_total', 'valor_adicional', 'valor_final']) && isset($data[$field])) {
                        $params[] = (float)$data[$field];
                    } else {
                        $params[] = $data[$field];
                    }
                }
            }
            
            if (empty($updateFields)) {
                return Response::json(['error' => 'Nenhum campo para atualizar'], 400);
            }
            
            $updateFields[] = 'updated_at = CURRENT_TIMESTAMP';
            $params[] = $id;
            
            $sql = "UPDATE locadora_contratos SET " . implode(', ', $updateFields) . " WHERE id = ?";
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute($params);
            
            AuditLogger::logUpdate('locadora_contratos', $id, [], $data);
            
            return Response::json(['data' => ['id' => $id, 'updated' => true]]);
        } catch (Exception $e) {
            return Response::json(['error' => $e->getMessage()], 500);
        }
    }
    
    public function encerrar(Request $r): Response {
        try {
            $id = (int)($r->params['id'] ?? 0);
            if ($id <= 0) {
                return Response::json(['error' => 'ID inválido'], 400);
            }
            
            $data = $r->body;
            $kmRetorno = (float)($data['km_retorno'] ?? 0);
            $dataDevolucao = $data['data_devolucao'] ?? date('Y-m-d');
            $valorAdicional = (float)($data['valor_adicional'] ?? 0);
            
            // Buscar contrato
            $contratoStmt = $this->pdo->prepare("
                SELECT c.*, v.id as veiculo_id, v.km_atual as veiculo_km
                FROM locadora_contratos c
                INNER JOIN locadora_frota v ON c.veiculo_id = v.id
                WHERE c.id = ?
            ");
            $contratoStmt->execute([$id]);
            $contrato = $contratoStmt->fetch(PDO::FETCH_ASSOC);
            
            if (!$contrato) {
                return Response::json(['error' => 'Contrato não encontrado'], 404);
            }
            
            if ($contrato['status'] === 'encerrado') {
                return Response::json(['error' => 'Contrato já está encerrado'], 400);
            }
            
            $kmSaida = (float)$contrato['km_saida'];
            $kmPercorrido = $kmRetorno - $kmSaida;
            
            if ($kmPercorrido < 0) {
                return Response::json(['error' => 'KM de retorno deve ser maior que KM de saída'], 400);
            }
            
            // Calcular valor final
            $valorTotal = (float)$contrato['valor_total'];
            $valorFinal = $valorTotal + $valorAdicional;
            
            $this->pdo->beginTransaction();
            
            // Atualizar contrato
            $updateStmt = $this->pdo->prepare("
                UPDATE locadora_contratos SET
                    status = 'encerrado',
                    data_devolucao = ?,
                    km_retorno = ?,
                    valor_adicional = ?,
                    valor_final = ?,
                    updated_at = CURRENT_TIMESTAMP
                WHERE id = ?
            ");
            $updateStmt->execute([$dataDevolucao, $kmRetorno, $valorAdicional, $valorFinal, $id]);
            
            // Atualizar veículo
            $updateVeiculoStmt = $this->pdo->prepare("
                UPDATE locadora_frota SET
                    status = 'disponivel',
                    km_atual = ?,
                    updated_at = CURRENT_TIMESTAMP
                WHERE id = ?
            ");
            $updateVeiculoStmt->execute([$kmRetorno, $contrato['veiculo_id']]);
            
            // Registrar KM de retorno
            $kmStmt = $this->pdo->prepare("
                INSERT INTO locadora_km_historico (veiculo_id, contrato_id, km_anterior, km_atual, km_percorrido, tipo)
                VALUES (?, ?, ?, ?, ?, 'retorno')
            ");
            $kmStmt->execute([$contrato['veiculo_id'], $id, $kmSaida, $kmRetorno, $kmPercorrido]);
            
            $this->pdo->commit();
            
            AuditLogger::logUpdate('locadora_contratos', $id, [], ['status' => 'encerrado']);
            
            return Response::json(['data' => ['id' => $id, 'encerrado' => true, 'km_percorrido' => $kmPercorrido, 'valor_final' => $valorFinal]]);
        } catch (Exception $e) {
            $this->pdo->rollBack();
            return Response::json(['error' => $e->getMessage()], 500);
        }
    }
    
    public function renovar(Request $r): Response {
        try {
            $id = (int)($r->params['id'] ?? 0);
            if ($id <= 0) {
                return Response::json(['error' => 'ID inválido'], 400);
            }
            
            $data = $r->body;
            $novaDataFim = $data['data_fim'] ?? '';
            
            if (empty($novaDataFim)) {
                return Response::json(['error' => 'Nova data de término é obrigatória'], 400);
            }
            
            // Buscar contrato
            $contratoStmt = $this->pdo->prepare("SELECT * FROM locadora_contratos WHERE id = ?");
            $contratoStmt->execute([$id]);
            $contrato = $contratoStmt->fetch(PDO::FETCH_ASSOC);
            
            if (!$contrato) {
                return Response::json(['error' => 'Contrato não encontrado'], 404);
            }
            
            $dataInicio = $contrato['data_inicio'];
            $quantidadeDias = max(1, (int)((strtotime($novaDataFim) - strtotime($dataInicio)) / 86400) + 1);
            $valorDiaria = (float)$contrato['valor_diaria'];
            $valorTotal = $valorDiaria * $quantidadeDias;
            
            $updateStmt = $this->pdo->prepare("
                UPDATE locadora_contratos SET
                    data_fim = ?,
                    quantidade_dias = ?,
                    valor_total = ?,
                    updated_at = CURRENT_TIMESTAMP
                WHERE id = ?
            ");
            $updateStmt->execute([$novaDataFim, $quantidadeDias, $valorTotal, $id]);
            
            AuditLogger::logUpdate('locadora_contratos', $id, [], ['renovado' => true, 'nova_data_fim' => $novaDataFim]);
            
            return Response::json(['data' => ['id' => $id, 'renovado' => true, 'nova_data_fim' => $novaDataFim, 'novo_valor_total' => $valorTotal]]);
        } catch (Exception $e) {
            return Response::json(['error' => $e->getMessage()], 500);
        }
    }
    
    public function getMultas(Request $r): Response {
        try {
            $id = (int)($r->params['id'] ?? 0);
            if ($id <= 0) {
                return Response::json(['error' => 'ID inválido'], 400);
            }
            
            $stmt = $this->pdo->prepare("
                SELECT * FROM locadora_multas 
                WHERE contrato_id = ? 
                ORDER BY data_ocorrencia DESC
            ");
            $stmt->execute([$id]);
            $multas = $stmt->fetchAll(PDO::FETCH_ASSOC);
            
            return Response::json(['data' => $multas]);
        } catch (Exception $e) {
            return Response::json(['error' => $e->getMessage()], 500);
        }
    }
    
    public function adicionarMulta(Request $r): Response {
        try {
            $id = (int)($r->params['id'] ?? 0);
            if ($id <= 0) {
                return Response::json(['error' => 'ID inválido'], 400);
            }
            
            $data = $r->body;
            
            // Buscar contrato para pegar veiculo_id
            $contratoStmt = $this->pdo->prepare("SELECT veiculo_id FROM locadora_contratos WHERE id = ?");
            $contratoStmt->execute([$id]);
            $contrato = $contratoStmt->fetch(PDO::FETCH_ASSOC);
            
            if (!$contrato) {
                return Response::json(['error' => 'Contrato não encontrado'], 404);
            }
            
            $this->pdo->beginTransaction();
            
            // Inserir multa
            $stmt = $this->pdo->prepare("
                INSERT INTO locadora_multas (
                    contrato_id, veiculo_id, tipo, descricao, data_ocorrencia,
                    valor, pago, data_pagamento, observacoes
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
            ");
            
            $stmt->execute([
                $id,
                $contrato['veiculo_id'],
                $data['tipo'] ?? 'multa',
                $data['descricao'] ?? '',
                $data['data_ocorrencia'] ?? date('Y-m-d'),
                (float)($data['valor'] ?? 0),
                (int)($data['pago'] ?? 0),
                $data['data_pagamento'] ?? null,
                $data['observacoes'] ?? null
            ]);
            
            $multaId = (int)$this->pdo->lastInsertId();
            
            // Atualizar valor adicional do contrato
            $multasStmt = $this->pdo->prepare("SELECT SUM(valor) as total FROM locadora_multas WHERE contrato_id = ?");
            $multasStmt->execute([$id]);
            $totalMultas = (float)($multasStmt->fetchColumn() ?? 0);
            
            $updateContratoStmt = $this->pdo->prepare("
                UPDATE locadora_contratos SET
                    valor_adicional = ?,
                    valor_final = valor_total + ?,
                    updated_at = CURRENT_TIMESTAMP
                WHERE id = ?
            ");
            $updateContratoStmt->execute([$totalMultas, $totalMultas, $id]);
            
            $this->pdo->commit();
            
            return Response::json(['data' => ['id' => $multaId]], 201);
        } catch (Exception $e) {
            $this->pdo->rollBack();
            return Response::json(['error' => $e->getMessage()], 500);
        }
    }
    
    private function gerarNumeroContrato(): string {
        $stmt = $this->pdo->query("SELECT MAX(CAST(SUBSTRING(numero, 5) AS UNSIGNED)) as max_num FROM locadora_contratos WHERE numero LIKE 'LOC-%'");
        $result = $stmt->fetch(PDO::FETCH_ASSOC);
        $nextNum = (int)($result['max_num'] ?? 0) + 1;
        return 'LOC-' . str_pad((string)$nextNum, 6, '0', STR_PAD_LEFT);
    }
}

