<?php
namespace Modules\GestorContratos\Controllers;

use Gestoreasy\Core\Http\Request;
use Gestoreasy\Core\Http\Response;
use Gestoreasy\Core\Tenant\TenantContext;
use Modules\GestorContratos\Services\ContratoService;
use Modules\GestorContratos\Services\NotificacaoService;
use Modules\GestorContratos\Services\EditorService;

class ContratosController {
    private function getTenantId(): string {
        return TenantContext::getTenantId();
    }

    /**
     * Lista contratos
     */
    public function list(Request $req): Response {
        try {
            $tenantId = $this->getTenantId();
            $service = new ContratoService($tenantId);

            $filtros = [
                'status' => $req->query['status'] ?? null,
                'tipo' => $req->query['tipo'] ?? null,
                'cliente_id' => $req->query['cliente_id'] ?? null,
                'numero' => $req->query['numero'] ?? null,
                'data_inicio' => $req->query['data_inicio'] ?? null,
                'data_fim' => $req->query['data_fim'] ?? null
            ];

            $page = max(1, (int)($req->query['page'] ?? 1));
            $perPage = min(100, max(1, (int)($req->query['per_page'] ?? 20)));

            $resultado = $service->listarContratos($filtros, $page, $perPage);

            return Response::json($resultado);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'error', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Busca um contrato por ID
     */
    public function get(Request $req): Response {
        try {
            $tenantId = $this->getTenantId();
            $service = new ContratoService($tenantId);

            $contratoId = (int)($req->get('params')[0] ?? 0);
            if (!$contratoId) {
                return new Response(422, ['error' => ['code' => 'invalid_id', 'message' => 'ID do contrato inválido']]);
            }

            $contrato = $service->buscarContrato($contratoId);
            if (!$contrato) {
                return new Response(404, ['error' => ['code' => 'not_found', 'message' => 'Contrato não encontrado']]);
            }

            return Response::json(['data' => $contrato]);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'error', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Cria um novo contrato
     */
    public function create(Request $req): Response {
        try {
            $tenantId = $this->getTenantId();
            $service = new ContratoService($tenantId);

            $body = is_array($req->body) ? $req->body : [];

            // Validar dados obrigatórios
            if (empty($body['titulo'])) {
                return new Response(422, ['error' => ['code' => 'invalid_data', 'message' => 'Título é obrigatório']]);
            }

            if (empty($body['conteudo_html'])) {
                return new Response(422, ['error' => ['code' => 'invalid_data', 'message' => 'Conteúdo é obrigatório']]);
            }

            // Preencher variáveis se houver dados de cliente/fornecedor/venda
            if (!empty($body['cliente_id']) || !empty($body['fornecedor_id']) || !empty($body['venda_id'])) {
                $editorService = new EditorService($tenantId);
                $dadosAutomaticos = $editorService->buscarTodosDados(
                    $body['cliente_id'] ?? null,
                    $body['fornecedor_id'] ?? null,
                    $body['venda_id'] ?? null
                );

                // Mesclar com variáveis fornecidas
                $body['variaveis_preenchidas'] = array_merge($dadosAutomaticos, $body['variaveis_preenchidas'] ?? []);
            }

            $contratoId = $service->criarContrato($body);

            return new Response(201, ['data' => ['id' => $contratoId, 'message' => 'Contrato criado com sucesso']]);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'error', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Atualiza um contrato
     */
    public function update(Request $req): Response {
        try {
            $tenantId = $this->getTenantId();
            $service = new ContratoService($tenantId);

            $contratoId = (int)($req->get('params')[0] ?? 0);
            if (!$contratoId) {
                return new Response(422, ['error' => ['code' => 'invalid_id', 'message' => 'ID do contrato inválido']]);
            }

            $body = is_array($req->body) ? $req->body : [];

            $service->atualizarContrato($contratoId, $body);

            return Response::json(['message' => 'Contrato atualizado com sucesso']);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'error', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Envia contrato para assinatura
     */
    public function enviarParaAssinatura(Request $req): Response {
        try {
            $tenantId = $this->getTenantId();
            $notificacaoService = new NotificacaoService($tenantId);

            $contratoId = (int)($req->get('params')[0] ?? 0);
            if (!$contratoId) {
                return new Response(422, ['error' => ['code' => 'invalid_id', 'message' => 'ID do contrato inválido']]);
            }

            $notificacaoService->enviarParaAssinatura($contratoId);

            return Response::json(['message' => 'Contrato enviado para assinatura com sucesso']);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'error', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Arquivar contrato
     */
    public function arquivar(Request $req): Response {
        try {
            $tenantId = $this->getTenantId();
            $service = new ContratoService($tenantId);

            $contratoId = (int)($req->get('params')[0] ?? 0);
            if (!$contratoId) {
                return new Response(422, ['error' => ['code' => 'invalid_id', 'message' => 'ID do contrato inválido']]);
            }

            $service->arquivarContrato($contratoId);

            return Response::json(['message' => 'Contrato arquivado com sucesso']);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'error', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Cancelar contrato
     */
    public function cancelar(Request $req): Response {
        try {
            $tenantId = $this->getTenantId();
            $service = new ContratoService($tenantId);

            $contratoId = (int)($req->get('params')[0] ?? 0);
            if (!$contratoId) {
                return new Response(422, ['error' => ['code' => 'invalid_id', 'message' => 'ID do contrato inválido']]);
            }

            $body = is_array($req->body) ? $req->body : [];
            $motivo = $body['motivo'] ?? null;

            $service->cancelarContrato($contratoId, $motivo);

            return Response::json(['message' => 'Contrato cancelado com sucesso']);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'error', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Busca dados para preenchimento automático
     */
    public function buscarDados(Request $req): Response {
        try {
            $tenantId = $this->getTenantId();
            $editorService = new EditorService($tenantId);

            $clienteId = $req->query['cliente_id'] ?? null;
            $fornecedorId = $req->query['fornecedor_id'] ?? null;
            $vendaId = $req->query['venda_id'] ?? null;

            $dados = $editorService->buscarTodosDados(
                $clienteId ? (int)$clienteId : null,
                $fornecedorId ? (int)$fornecedorId : null,
                $vendaId ? (int)$vendaId : null
            );

            return Response::json(['data' => $dados]);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'error', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Busca histórico do contrato
     */
    public function historico(Request $req): Response {
        try {
            $tenantId = $this->getTenantId();
            $pdo = \Gestoreasy\Core\Tenant\ConnectionManager::forTenant($tenantId);

            $contratoId = (int)($req->get('params')[0] ?? 0);
            if (!$contratoId) {
                return new Response(422, ['error' => ['code' => 'invalid_id', 'message' => 'ID do contrato inválido']]);
            }

            $stmt = $pdo->prepare('
                SELECT * FROM contratos_historico
                WHERE contrato_id = ?
                ORDER BY created_at DESC
            ');
            $stmt->execute([$contratoId]);
            $historico = $stmt->fetchAll(\PDO::FETCH_ASSOC);

            return Response::json(['data' => $historico]);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'error', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Dashboard de estatísticas
     */
    public function dashboard(Request $req): Response {
        try {
            $tenantId = $this->getTenantId();
            $pdo = \Gestoreasy\Core\Tenant\ConnectionManager::forTenant($tenantId);

            // Contratos por status
            $stmt = $pdo->prepare('
                SELECT status, COUNT(*) as total
                FROM contratos
                WHERE tenant_id = ?
                GROUP BY status
            ');
            $stmt->execute([$tenantId]);
            $porStatus = $stmt->fetchAll(\PDO::FETCH_ASSOC);

            // Contratos pendentes de assinatura
            $stmt = $pdo->prepare('
                SELECT COUNT(*) as total
                FROM contratos
                WHERE tenant_id = ? AND status = "pendente_assinatura"
            ');
            $stmt->execute([$tenantId]);
            $pendentes = $stmt->fetch(\PDO::FETCH_ASSOC);

            // Contratos vencendo em 30 dias
            $stmt = $pdo->prepare('
                SELECT COUNT(*) as total
                FROM contratos
                WHERE tenant_id = ? AND status = "assinado"
                AND data_vencimento BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 30 DAY)
            ');
            $stmt->execute([$tenantId]);
            $vencendo = $stmt->fetch(\PDO::FETCH_ASSOC);

            // Contratos expirados
            $stmt = $pdo->prepare('
                SELECT COUNT(*) as total
                FROM contratos
                WHERE tenant_id = ? AND status = "expirado"
            ');
            $stmt->execute([$tenantId]);
            $expirados = $stmt->fetch(\PDO::FETCH_ASSOC);

            return Response::json([
                'data' => [
                    'por_status' => $porStatus,
                    'pendentes_assinatura' => (int)($pendentes['total'] ?? 0),
                    'vencendo_30_dias' => (int)($vencendo['total'] ?? 0),
                    'expirados' => (int)($expirados['total'] ?? 0)
                ]
            ]);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'error', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Gera contrato automaticamente a partir de um pedido de venda
     */
    public function gerarDeVenda(Request $req): Response {
        try {
            $tenantId = $this->getTenantId();
            $integraService = new \Modules\GestorContratos\Services\IntegracaoService($tenantId);

            $vendaId = (int)($req->get('params')[0] ?? 0);
            if (!$vendaId) {
                return new Response(422, ['error' => ['code' => 'invalid_id', 'message' => 'ID da venda inválido']]);
            }

            $body = is_array($req->body) ? $req->body : [];
            $modeloId = !empty($body['modelo_id']) ? (int)$body['modelo_id'] : null;

            $contratoId = $integraService->gerarContratoDeVenda($vendaId, $modeloId);

            return Response::json(['data' => ['contrato_id' => $contratoId]], 201);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'error', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Gera contrato automaticamente a partir de uma conta financeira
     */
    public function gerarDeFinanceiro(Request $req): Response {
        try {
            $tenantId = $this->getTenantId();
            $integraService = new \Modules\GestorContratos\Services\IntegracaoService($tenantId);

            $financeiroId = (int)($req->get('params')[0] ?? 0);
            if (!$financeiroId) {
                return new Response(422, ['error' => ['code' => 'invalid_id', 'message' => 'ID financeiro inválido']]);
            }

            $body = is_array($req->body) ? $req->body : [];
            $tipo = $body['tipo'] ?? 'receber'; // receber ou pagar
            $modeloId = !empty($body['modelo_id']) ? (int)$body['modelo_id'] : null;

            $contratoId = $integraService->gerarContratoFinanceiro($financeiroId, $tipo, $modeloId);

            return Response::json(['data' => ['contrato_id' => $contratoId]], 201);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'error', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Vincula contrato a uma conta financeira
     */
    public function vincularFinanceiro(Request $req): Response {
        try {
            $tenantId = $this->getTenantId();
            $integraService = new \Modules\GestorContratos\Services\IntegracaoService($tenantId);

            $contratoId = (int)($req->get('params')[0] ?? 0);
            if (!$contratoId) {
                return new Response(422, ['error' => ['code' => 'invalid_id', 'message' => 'ID do contrato inválido']]);
            }

            $body = is_array($req->body) ? $req->body : [];
            $financeiroId = (int)($body['financeiro_id'] ?? 0);
            $tipo = $body['tipo'] ?? 'receber';

            if (!$financeiroId) {
                return new Response(422, ['error' => ['code' => 'invalid_data', 'message' => 'ID financeiro é obrigatório']]);
            }

            $integraService->vincularContratoFinanceiro($contratoId, $financeiroId, $tipo);

            return Response::json(['data' => ['success' => true]]);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'error', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Gera PDF do contrato
     */
    public function gerarPdf(Request $req): Response {
        try {
            $tenantId = $this->getTenantId();
            $pdfService = new \Modules\GestorContratos\Services\PdfService($tenantId);

            $contratoId = (int)($req->get('params')[0] ?? 0);
            if (!$contratoId) {
                return new Response(422, ['error' => ['code' => 'invalid_id', 'message' => 'ID do contrato inválido']]);
            }

            $incluirAssinaturas = ($req->query['assinaturas'] ?? 'true') === 'true';
            $pdfContent = $pdfService->gerarPdf($contratoId, $incluirAssinaturas);

            // Retornar como base64 para facilitar uso no frontend
            return Response::json([
                'data' => [
                    'pdf_base64' => base64_encode($pdfContent),
                    'tamanho' => strlen($pdfContent)
                ]
            ]);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'error', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Download do PDF do contrato
     */
    public function downloadPdf(Request $req): Response {
        try {
            $tenantId = $this->getTenantId();
            $pdfService = new \Modules\GestorContratos\Services\PdfService($tenantId);

            $contratoId = (int)($req->get('params')[0] ?? 0);
            if (!$contratoId) {
                return new Response(422, ['error' => ['code' => 'invalid_id', 'message' => 'ID do contrato inválido']]);
            }

            $incluirAssinaturas = ($req->query['assinaturas'] ?? 'true') === 'true';
            $pdfContent = $pdfService->gerarPdf($contratoId, $incluirAssinaturas);

            // Buscar número do contrato para nome do arquivo
            $pdo = \Gestoreasy\Core\Tenant\ConnectionManager::forTenant($tenantId);
            $stmt = $pdo->prepare('SELECT numero FROM contratos WHERE id = ? AND tenant_id = ?');
            $stmt->execute([$contratoId, $tenantId]);
            $contrato = $stmt->fetch(\PDO::FETCH_ASSOC);
            $nomeArquivo = 'Contrato_' . ($contrato['numero'] ?? $contratoId) . '.pdf';

            // Retornar PDF como download
            header('Content-Type: application/pdf');
            header('Content-Disposition: attachment; filename="' . $nomeArquivo . '"');
            header('Content-Length: ' . strlen($pdfContent));
            echo $pdfContent;
            exit;
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'error', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Valida integridade da assinatura digital do contrato
     */
    public function validarAssinatura(Request $req): Response {
        try {
            $tenantId = $this->getTenantId();
            $assinaturaService = new \Modules\GestorContratos\Services\AssinaturaService($tenantId);

            $contratoId = (int)($req->get('params')[0] ?? 0);
            if (!$contratoId) {
                return new Response(422, ['error' => ['code' => 'invalid_id', 'message' => 'ID do contrato inválido']]);
            }

            $validacao = $assinaturaService->validarIntegridadeAssinatura($contratoId);

            return Response::json(['data' => $validacao]);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'error', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Obtém informações do certificado digital usado na assinatura
     */
    public function obterCertificadoDigital(Request $req): Response {
        try {
            $tenantId = $this->getTenantId();
            $pdo = \Gestoreasy\Core\Tenant\ConnectionManager::forTenant($tenantId);

            $contratoId = (int)($req->get('params')[0] ?? 0);
            if (!$contratoId) {
                return new Response(422, ['error' => ['code' => 'invalid_id', 'message' => 'ID do contrato inválido']]);
            }

            // Buscar informações de certificados dos signatários
            $stmt = $pdo->prepare('
                SELECT cs.nome, cs.email, cs.certificado_digital, cs.data_assinatura,
                       cs.assinatura_digital, cs.ip_assinatura
                FROM contratos_signatarios cs
                INNER JOIN contratos c ON cs.contrato_id = c.id
                WHERE cs.contrato_id = ? AND cs.status = "assinado" 
                AND c.tenant_id = ? AND cs.certificado_digital IS NOT NULL
            ');
            $stmt->execute([$contratoId, $tenantId]);
            $certificados = $stmt->fetchAll(\PDO::FETCH_ASSOC);

            return Response::json(['data' => $certificados]);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'error', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Renova um contrato
     */
    public function renovar(Request $req): Response {
        try {
            $tenantId = $this->getTenantId();
            $service = new ContratoService($tenantId);

            $contratoId = (int)($req->get('params')[0] ?? 0);
            if (!$contratoId) {
                return new Response(422, ['error' => ['code' => 'invalid_id', 'message' => 'ID do contrato inválido']]);
            }

            $body = is_array($req->body) ? $req->body : [];
            $manterTermos = $body['manter_termos'] ?? true;
            $novaDataInicio = $body['data_inicio'] ?? date('Y-m-d');
            $novaDataFim = $body['data_fim'] ?? null;

            $novoContratoId = $service->renovarContrato($contratoId, [
                'manter_termos' => $manterTermos,
                'data_inicio' => $novaDataInicio,
                'data_fim' => $novaDataFim
            ]);

            return Response::json(['data' => ['contrato_id' => $novoContratoId]], 201);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'error', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Busca configurações do módulo
     */
    public function getConfig(Request $req): Response {
        try {
            $tenantId = $this->getTenantId();
            $pdo = \Gestoreasy\Core\Tenant\ConnectionManager::forTenant($tenantId);

            $stmt = $pdo->prepare('SELECT * FROM contratos_config WHERE tenant_id = ?');
            $stmt->execute([$tenantId]);
            $config = $stmt->fetch(\PDO::FETCH_ASSOC);

            if (!$config) {
                // Criar configuração padrão
                $stmt = $pdo->prepare('
                    INSERT INTO contratos_config (tenant_id) VALUES (?)
                ');
                $stmt->execute([$tenantId]);
                $config = [
                    'usar_assinatura_digital' => true,
                    'usar_certificado_icp_brasil' => false,
                    'dias_expiracao' => 30,
                    'enviar_notificacoes' => true,
                    'enviar_lembretes' => true,
                    'dias_lembrete' => 3,
                    'max_lembretes' => 3
                ];
            }

            return Response::json(['data' => $config]);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'error', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Atualiza configurações do módulo
     */
    public function updateConfig(Request $req): Response {
        try {
            $tenantId = $this->getTenantId();
            $pdo = \Gestoreasy\Core\Tenant\ConnectionManager::forTenant($tenantId);

            $body = is_array($req->body) ? $req->body : [];

            // Verificar se já existe
            $stmt = $pdo->prepare('SELECT id FROM contratos_config WHERE tenant_id = ?');
            $stmt->execute([$tenantId]);
            $existe = $stmt->fetch();

            if ($existe) {
                // Atualizar
                $campos = [];
                $valores = [];
                
                $camposPermitidos = [
                    'usar_assinatura_digital', 'usar_certificado_icp_brasil', 'dias_expiracao',
                    'enviar_notificacoes', 'enviar_lembretes', 'dias_lembrete',
                    'max_lembretes', 'requer_certificado_digital', 'criptografar_arquivos',
                    'hash_algoritmo', 'renovacao_automatica', 'dias_antes_renovacao'
                ];

                foreach ($camposPermitidos as $campo) {
                    if (isset($body[$campo])) {
                        $campos[] = "{$campo} = :{$campo}";
                        $valores[":{$campo}"] = $body[$campo];
                    }
                }

                if (!empty($campos)) {
                    $valores[':tenant_id'] = $tenantId;
                    $sql = 'UPDATE contratos_config SET ' . implode(', ', $campos) . ' WHERE tenant_id = :tenant_id';
                    $stmt = $pdo->prepare($sql);
                    $stmt->execute($valores);
                }
            } else {
                // Criar
                $stmt = $pdo->prepare('
                    INSERT INTO contratos_config (tenant_id, usar_assinatura_digital, usar_certificado_icp_brasil, 
                        dias_expiracao, enviar_notificacoes, enviar_lembretes, dias_lembrete, max_lembretes)
                    VALUES (?, ?, ?, ?, ?, ?, ?, ?)
                ');
                $stmt->execute([
                    $tenantId,
                    $body['usar_assinatura_digital'] ?? true ? 1 : 0,
                    $body['usar_certificado_icp_brasil'] ?? false ? 1 : 0,
                    $body['dias_expiracao'] ?? 30,
                    $body['enviar_notificacoes'] ?? true ? 1 : 0,
                    $body['enviar_lembretes'] ?? true ? 1 : 0,
                    $body['dias_lembrete'] ?? 3,
                    $body['max_lembretes'] ?? 3
                ]);
            }

            return Response::json(['data' => ['success' => true]]);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'error', 'message' => $e->getMessage()]]);
        }
    }
}

