<?php
namespace Modules\Fiscal\Controllers;

use Gestoreasy\Core\Http\Request;
use Gestoreasy\Core\Http\Response;
use Gestoreasy\Core\Tenant\ConnectionManager;
use Gestoreasy\Core\Tenant\TenantContext;
use Gestoreasy\Core\Auth\AuthMiddleware;
use Gestoreasy\Core\Auth\Rbac;
use Gestoreasy\Core\Audit\AuditLogger;
use Modules\Fiscal\Services\NFeEntradaService;
use Modules\Fiscal\Services\NFeDeteccaoService;

class NFeEntradaController {
    private string $tenantId;

    public function __construct() {
        $this->tenantId = TenantContext::getTenantId();
    }

    /**
     * Lista notas fiscais de entrada
     */
    public function list(Request $req): Response {
        try {
            $pdo = ConnectionManager::forTenant();
            $page = max(1, (int)($req->query['page'] ?? 1));
            $perPage = min(100, max(1, (int)($req->query['per_page'] ?? 20)));
            $offset = ($page - 1) * $perPage;
            
            $where = ['tenant_id = ?'];
            $params = [$this->tenantId];
            
            // Filtros
            if (!empty($req->query['status'])) {
                $where[] = 'status = ?';
                $params[] = $req->query['status'];
            }
            if (!empty($req->query['fornecedor_id'])) {
                $where[] = 'fornecedor_id = ?';
                $params[] = (int)$req->query['fornecedor_id'];
            }
            if (!empty($req->query['chave'])) {
                $where[] = 'chave_acesso LIKE ?';
                $params[] = '%' . $req->query['chave'] . '%';
            }
            if (!empty($req->query['numero'])) {
                $where[] = 'numero LIKE ?';
                $params[] = '%' . $req->query['numero'] . '%';
            }
            
            $whereSql = 'WHERE ' . implode(' AND ', $where);
            
            // Contar total
            $countStmt = $pdo->prepare("SELECT COUNT(*) AS total FROM nfe_entrada $whereSql");
            $countStmt->execute($params);
            $total = (int)$countStmt->fetch()['total'];
            
            // Buscar notas
            $stmt = $pdo->prepare("SELECT n.*, s.nome AS fornecedor_nome 
                FROM nfe_entrada n 
                LEFT JOIN suppliers s ON s.id = n.fornecedor_id 
                $whereSql 
                ORDER BY n.data_emissao DESC, n.id DESC 
                LIMIT ? OFFSET ?");
            $params[] = $perPage;
            $params[] = $offset;
            $stmt->execute($params);
            $notas = $stmt->fetchAll();
            
            AuditLogger::logRead('nfe_entrada', null, ['page' => $page, 'per_page' => $perPage]);
            
            return Response::json([
                'data' => $notas,
                'page' => $page,
                'per_page' => $perPage,
                'total' => $total,
                'total_pages' => (int)ceil($total / $perPage)
            ]);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'list_failed', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Obtém uma nota fiscal por ID
     */
    public function getById(Request $req): Response {
        try {
            $id = (int)($req->get('params', [])[0] ?? 0);
            if ($id <= 0) {
                return new Response(422, ['error' => ['code' => 'invalid_id', 'message' => 'ID inválido']]);
            }
            
            $pdo = ConnectionManager::forTenant();
            $stmt = $pdo->prepare('SELECT n.*, s.nome AS fornecedor_nome 
                FROM nfe_entrada n 
                LEFT JOIN suppliers s ON s.id = n.fornecedor_id 
                WHERE n.id = ? AND n.tenant_id = ? LIMIT 1');
            $stmt->execute([$id, $this->tenantId]);
            $nota = $stmt->fetch();
            
            if (!$nota) {
                return new Response(404, ['error' => ['code' => 'not_found', 'message' => 'Nota fiscal não encontrada']]);
            }
            
            // Buscar itens
            $stmt = $pdo->prepare('SELECT i.*, p.descricao AS product_descricao 
                FROM nfe_entrada_itens i 
                LEFT JOIN products p ON p.id = i.product_id 
                WHERE i.nfe_entrada_id = ? 
                ORDER BY i.numero_item');
            $stmt->execute([$id]);
            $itens = $stmt->fetchAll();
            
            $nota['itens'] = $itens;
            
            AuditLogger::logRead('nfe_entrada', $id);
            
            return Response::json(['data' => $nota]);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'get_failed', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Cria nota fiscal manualmente
     */
    public function createManual(Request $req): Response {
        try {
            $body = $req->body;
            
            // Validar campos obrigatórios
            $required = ['chave_acesso', 'numero', 'serie', 'emitente_cnpj', 'emitente_nome', 'destinatario_cnpj', 'destinatario_nome', 'data_emissao', 'valor_total'];
            foreach ($required as $field) {
                if (empty($body[$field])) {
                    return new Response(422, ['error' => ['code' => 'missing_field', 'message' => "Campo obrigatório: $field"]]);
                }
            }
            
            // Validar chave de acesso
            $chave = preg_replace('/\D/', '', $body['chave_acesso']);
            if (strlen($chave) !== 44) {
                return new Response(422, ['error' => ['code' => 'invalid_chave', 'message' => 'Chave de acesso deve ter 44 dígitos']]);
            }
            
            $service = new NFeEntradaService();
            
            // Preparar dados
            $dados = [
                'chave_acesso' => $chave,
                'numero' => $body['numero'],
                'serie' => $body['serie'],
                'modelo' => $body['modelo'] ?? '55',
                'tipo_emissao' => $body['tipo_emissao'] ?? 1,
                'data_emissao' => $body['data_emissao'],
                'emitente' => [
                    'cnpj' => preg_replace('/\D/', '', $body['emitente_cnpj']),
                    'nome' => $body['emitente_nome'],
                    'ie' => $body['emitente_ie'] ?? null,
                    'endereco' => $body['emitente_endereco'] ?? null
                ],
                'destinatario' => [
                    'cnpj' => preg_replace('/\D/', '', $body['destinatario_cnpj']),
                    'nome' => $body['destinatario_nome'],
                    'ie' => $body['destinatario_ie'] ?? null,
                    'endereco' => $body['destinatario_endereco'] ?? null
                ],
                'valores' => [
                    'produtos' => (float)($body['valor_produtos'] ?? $body['valor_total']),
                    'desconto' => (float)($body['valor_desconto'] ?? 0),
                    'frete' => (float)($body['valor_frete'] ?? 0),
                    'seguro' => (float)($body['valor_seguro'] ?? 0),
                    'outras_despesas' => (float)($body['valor_outras_despesas'] ?? 0),
                    'total' => (float)$body['valor_total'],
                    'icms' => (float)($body['valor_icms'] ?? 0),
                    'ipi' => (float)($body['valor_ipi'] ?? 0),
                    'pis' => (float)($body['valor_pis'] ?? 0),
                    'cofins' => (float)($body['valor_cofins'] ?? 0)
                ],
                'itens' => $body['itens'] ?? [],
                'protocolo' => $body['protocolo_autorizacao'] ?? null
            ];
            
            $nfeId = $service->salvarNota($dados, 'manual', $body['fornecedor_id'] ?? null);
            
            AuditLogger::logCreate('nfe_entrada', $nfeId, ['forma' => 'manual', 'chave' => $chave]);
            
            return Response::json(['ok' => true, 'id' => $nfeId], 201);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'create_failed', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Importa nota fiscal via XML
     */
    public function importarXml(Request $req): Response {
        try {
            $body = $req->body;
            $xmlContent = $body['xml'] ?? '';
            
            if (empty($xmlContent)) {
                // Tentar receber via upload
                if (!empty($req->files['xml_file'])) {
                    $file = $req->files['xml_file'];
                    $xmlContent = file_get_contents($file['tmp_name']);
                } else {
                    return new Response(422, ['error' => ['code' => 'xml_required', 'message' => 'XML é obrigatório']]);
                }
            }
            
            $service = new NFeEntradaService();
            $dados = $service->processarXml($xmlContent);
            
            $nfeId = $service->salvarNota($dados, 'xml', $body['fornecedor_id'] ?? null);
            
            AuditLogger::logCreate('nfe_entrada', $nfeId, ['forma' => 'xml', 'chave' => $dados['chave_acesso']]);
            
            return Response::json(['ok' => true, 'id' => $nfeId, 'data' => $dados], 201);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'import_failed', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Consulta nota por chave de acesso
     */
    public function consultarChave(Request $req): Response {
        try {
            $body = $req->body;
            $chave = preg_replace('/\D/', '', $body['chave_acesso'] ?? '');
            
            if (strlen($chave) !== 44) {
                return new Response(422, ['error' => ['code' => 'invalid_chave', 'message' => 'Chave de acesso deve ter 44 dígitos']]);
            }
            
            $ambiente = $body['ambiente'] ?? 'producao';
            $service = new NFeEntradaService();
            
            try {
                $dados = $service->consultarPorChave($chave, $ambiente);
                
                // Se dados completos retornados, oferecer opção de salvar
                if (isset($dados['numero']) && isset($dados['emitente'])) {
                    return Response::json(['ok' => true, 'data' => $dados, 'pode_salvar' => true]);
                }
                
                return Response::json(['ok' => true, 'data' => $dados, 'pode_salvar' => false]);
            } catch (\Exception $e) {
                // Se não conseguir consultar, retornar erro
                return new Response(500, ['error' => ['code' => 'consult_failed', 'message' => $e->getMessage()]]);
            }
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'consult_error', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Processa nota fiscal (integra com compras, estoque e financeiro)
     */
    public function processar(Request $req): Response {
        try {
            $id = (int)($req->get('params', [])[0] ?? 0);
            if ($id <= 0) {
                return new Response(422, ['error' => ['code' => 'invalid_id', 'message' => 'ID inválido']]);
            }
            
            $body = $req->body;
            $criarContaPagar = $body['criar_conta_pagar'] ?? true;
            
            $service = new NFeEntradaService();
            $resultado = $service->processarNota($id, $criarContaPagar);
            
            AuditLogger::logUpdate('nfe_entrada', $id, ['acao' => 'processar', 'resultado' => $resultado]);
            
            return Response::json(['ok' => true, 'data' => $resultado]);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'process_failed', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Configura detecção automática
     */
    public function configurarDeteccao(Request $req): Response {
        try {
            $body = $req->body;
            $cnpj = preg_replace('/\D/', '', $body['cnpj_empresa'] ?? '');
            
            if (strlen($cnpj) !== 14) {
                return new Response(422, ['error' => ['code' => 'invalid_cnpj', 'message' => 'CNPJ inválido']]);
            }
            
            $service = new NFeDeteccaoService();
            $config = $service->configurar($cnpj, $body);
            
            return Response::json(['ok' => true, 'data' => $config]);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'config_failed', 'message' => $e->getMessage()]]);
        }
    }

    /**
     * Executa detecção automática
     */
    public function executarDeteccao(Request $req): Response {
        try {
            $service = new NFeDeteccaoService();
            $resultado = $service->executar();
            
            return Response::json(['ok' => true, 'data' => $resultado]);
        } catch (\Exception $e) {
            return new Response(500, ['error' => ['code' => 'detection_failed', 'message' => $e->getMessage()]]);
        }
    }
}

