<?php
namespace Modules\Ecommerce\Services;

use Gestoreasy\Core\Tenant\ConnectionManager;
use Gestoreasy\Core\Tenant\TenantContext;
use Gestoreasy\Core\Validation\Br;
use Gestoreasy\Core\Audit\AuditLogger;
use PDO;

class EcommerceIntegrationService {
    private PDO $pdo;
    private string $tenantId;

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

    /**
     * Busca ou cria cliente a partir dos dados do pedido do e-commerce
     */
    public function findOrCreateCliente(array $clienteData, array $enderecoData): ?int {
        $email = trim($clienteData['email'] ?? '');
        $cpf = isset($clienteData['cpf']) ? preg_replace('/\D/', '', $clienteData['cpf']) : null;
        
        if (empty($email)) {
            return null;
        }

        // Tentar buscar por email primeiro
        $stmt = $this->pdo->prepare('SELECT id FROM clients WHERE email = ? LIMIT 1');
        $stmt->execute([$email]);
        $cliente = $stmt->fetch();
        
        if ($cliente) {
            return (int)$cliente['id'];
        }

        // Tentar buscar por CPF se fornecido
        if ($cpf && Br::isCPF($cpf)) {
            $stmt = $this->pdo->prepare('SELECT id FROM clients WHERE cpf = ? LIMIT 1');
            $stmt->execute([$cpf]);
            $cliente = $stmt->fetch();
            
            if ($cliente) {
                return (int)$cliente['id'];
            }
        }

        // Criar novo cliente
        $nome = trim($clienteData['nome'] ?? 'Cliente E-commerce');
        $tipo = ($cpf && Br::isCPF($cpf)) ? 'PF' : 'PJ';
        $telefone = $clienteData['telefone'] ?? null;
        
        // Preparar dados do cliente
        $razaoSocial = $nome;
        $nomeFantasia = $nome;
        $ie = 'ISENTO'; // Para clientes PF do e-commerce
        $im = null;
        
        try {
            $stmt = $this->pdo->prepare('INSERT INTO clients 
                (nome, nome_fantasia, razao_social, tipo, cpf, cnpj, ie, im, email, telefone_fixo, telefone_celular, inativo)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
            
            $stmt->execute([
                $nome,
                $nomeFantasia,
                $razaoSocial,
                $tipo,
                $tipo === 'PF' ? $cpf : null,
                $tipo === 'PJ' ? $cpf : null, // Se for CNPJ, ajustar depois
                $ie,
                $im,
                $email,
                $telefone,
                $telefone,
                0 // Não inativo
            ]);
            
            $clienteId = (int)$this->pdo->lastInsertId();
            
            // Criar endereço se fornecido
            if (!empty($enderecoData)) {
                $this->createClienteEndereco($clienteId, $enderecoData);
            }
            
            AuditLogger::log('create', 'clients', $clienteId, [
                'source' => 'ecommerce',
                'email' => $email
            ]);
            
            return $clienteId;
        } catch (\PDOException $e) {
            error_log("[EcommerceIntegration] Erro ao criar cliente: " . $e->getMessage());
            return null;
        }
    }

    /**
     * Cria endereço para o cliente
     */
    private function createClienteEndereco(int $clienteId, array $enderecoData): void {
        try {
            // Verificar se já existe endereço principal
            $stmt = $this->pdo->prepare('SELECT id FROM client_addresses WHERE client_id = ? AND tipo = "principal" LIMIT 1');
            $stmt->execute([$clienteId]);
            $enderecoPrincipal = $stmt->fetch();
            
            // Se não existe endereço principal, criar como principal, senão criar como entrega
            $tipo = $enderecoPrincipal ? 'entrega' : 'principal';
            
            $stmt = $this->pdo->prepare('INSERT INTO client_addresses 
                (client_id, tipo, logradouro, numero, complemento, bairro, cidade, estado, cep)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)');
            
            $stmt->execute([
                $clienteId,
                $tipo,
                $enderecoData['endereco'] ?? $enderecoData['logradouro'] ?? '',
                $enderecoData['numero'] ?? '',
                $enderecoData['complemento'] ?? null,
                $enderecoData['bairro'] ?? '',
                $enderecoData['cidade'] ?? '',
                $enderecoData['estado'] ?? '',
                preg_replace('/\D/', '', $enderecoData['cep'] ?? '')
            ]);
        } catch (\PDOException $e) {
            error_log("[EcommerceIntegration] Erro ao criar endereço: " . $e->getMessage());
        }
    }

    /**
     * Valida estoque disponível para os produtos do pedido
     */
    public function validateEstoque(array $produtos): array {
        $errors = [];
        $produtosValidados = [];
        
        foreach ($produtos as $item) {
            $productId = (int)($item['id'] ?? 0);
            $quantidade = (int)($item['quantidade'] ?? 1);
            
            if ($productId <= 0) {
                $errors[] = ['product_id' => $productId, 'message' => 'ID de produto inválido'];
                continue;
            }
            
            $stmt = $this->pdo->prepare('SELECT id, codigo, nome, estoque, preco FROM products WHERE id = ? LIMIT 1');
            $stmt->execute([$productId]);
            $produto = $stmt->fetch();
            
            if (!$produto) {
                $errors[] = ['product_id' => $productId, 'message' => 'Produto não encontrado'];
                continue;
            }
            
            $estoqueDisponivel = (float)($produto['estoque'] ?? 0);
            
            if ($estoqueDisponivel < $quantidade) {
                $errors[] = [
                    'product_id' => $productId,
                    'codigo' => $produto['codigo'],
                    'nome' => $produto['nome'],
                    'message' => "Estoque insuficiente. Disponível: $estoqueDisponivel, Solicitado: $quantidade",
                    'disponivel' => $estoqueDisponivel,
                    'solicitado' => $quantidade
                ];
                continue;
            }
            
            $produtosValidados[] = [
                'product_id' => $productId,
                'quantidade' => $quantidade,
                'produto' => $produto
            ];
        }
        
        return ['valid' => empty($errors), 'errors' => $errors, 'produtos' => $produtosValidados];
    }

    /**
     * Cria pedido de venda (sales_orders) a partir de pedido do e-commerce
     */
    public function createSalesOrderFromEcommerce(int $ecommercePedidoId): ?int {
        try {
            // Buscar pedido do e-commerce
            $stmt = $this->pdo->prepare('SELECT * FROM ecommerce_pedidos WHERE id = ? AND tenant_id = ? LIMIT 1');
            $stmt->execute([$ecommercePedidoId, $this->tenantId]);
            $pedidoEcommerce = $stmt->fetch();
            
            if (!$pedidoEcommerce) {
                return null;
            }
            
            // Buscar ou criar cliente
            $clienteData = [
                'nome' => $pedidoEcommerce['cliente_nome'],
                'email' => $pedidoEcommerce['cliente_email'],
                'telefone' => $pedidoEcommerce['cliente_telefone'],
                'cpf' => $pedidoEcommerce['cliente_cpf']
            ];
            
            $enderecoData = json_decode($pedidoEcommerce['endereco_entrega'] ?? '{}', true);
            $clienteId = $this->findOrCreateCliente($clienteData, $enderecoData);
            
            if (!$clienteId) {
                error_log("[EcommerceIntegration] Não foi possível criar/buscar cliente para pedido $ecommercePedidoId");
                return null;
            }
            
            // Buscar itens do pedido
            $stmt = $this->pdo->prepare('SELECT * FROM ecommerce_pedido_itens WHERE pedido_id = ?');
            $stmt->execute([$ecommercePedidoId]);
            $itens = $stmt->fetchAll();
            
            if (empty($itens)) {
                return null;
            }
            
            // Gerar número do pedido de venda
            $numero = null;
            try {
                $stmtSeq = $this->pdo->query("SELECT MAX(CAST(SUBSTRING(numero, 4) AS UNSIGNED)) AS max_seq FROM sales_orders WHERE numero LIKE 'PD-%'");
                $rowSeq = $stmtSeq->fetch();
                $next = ((int)($rowSeq['max_seq'] ?? 0)) + 1;
                $numero = 'PD-' . str_pad((string)$next, 10, '0', STR_PAD_LEFT);
            } catch (\Throwable $e) {
                $numero = null;
            }
            
            $this->pdo->beginTransaction();
            
            // Criar pedido de venda
            $valorTotal = (float)$pedidoEcommerce['total'];
            $status = 'aberto'; // Pedido do e-commerce vira pedido aberto no sistema
            
            if ($numero !== null) {
                $stmt = $this->pdo->prepare('INSERT INTO sales_orders (numero, cliente_id, valor_total, status, ecommerce_pedido_id) VALUES (?, ?, ?, ?, ?)');
                $stmt->execute([$numero, $clienteId, $valorTotal, $status, $ecommercePedidoId]);
            } else {
                $stmt = $this->pdo->prepare('INSERT INTO sales_orders (numero, cliente_id, valor_total, status, ecommerce_pedido_id) VALUES (?, ?, ?, ?, ?)');
                $stmt->execute(['', $clienteId, $valorTotal, $status, $ecommercePedidoId]);
                $newId = (int)$this->pdo->lastInsertId();
                $numero = 'PD-' . str_pad((string)$newId, 10, '0', STR_PAD_LEFT);
                $this->pdo->prepare('UPDATE sales_orders SET numero = ? WHERE id = ?')->execute([$numero, $newId]);
            }
            
            $salesOrderId = (int)$this->pdo->lastInsertId();
            
            // Criar itens do pedido de venda
            foreach ($itens as $item) {
                try {
                    $stmt = $this->pdo->prepare('INSERT INTO sales_order_items (order_id, product_id, quantidade, preco, total) VALUES (?, ?, ?, ?, ?)');
                    $stmt->execute([
                        $salesOrderId,
                        (int)$item['product_id'],
                        (float)$item['quantidade'],
                        (float)$item['preco_unitario'],
                        (float)$item['subtotal']
                    ]);
                } catch (\Throwable $e) {
                    error_log("[EcommerceIntegration] Erro ao criar item: " . $e->getMessage());
                }
            }
            
            // Atualizar pedido do e-commerce com referência ao pedido de venda
            try {
                $this->pdo->query("ALTER TABLE ecommerce_pedidos ADD COLUMN sales_order_id BIGINT UNSIGNED NULL")->execute();
            } catch (\Throwable $e) {}
            
            $stmt = $this->pdo->prepare('UPDATE ecommerce_pedidos SET sales_order_id = ? WHERE id = ?');
            $stmt->execute([$salesOrderId, $ecommercePedidoId]);
            
            $this->pdo->commit();
            
            AuditLogger::log('create', 'sales_orders', $salesOrderId, [
                'source' => 'ecommerce',
                'ecommerce_pedido_id' => $ecommercePedidoId
            ]);
            
            return $salesOrderId;
        } catch (\Throwable $e) {
            if ($this->pdo->inTransaction()) {
                $this->pdo->rollBack();
            }
            error_log("[EcommerceIntegration] Erro ao criar pedido de venda: " . $e->getMessage());
            return null;
        }
    }

    /**
     * Baixa estoque quando pedido é confirmado
     */
    public function baixarEstoque(int $ecommercePedidoId, bool $allowNegative = false): bool {
        try {
            $stmt = $this->pdo->prepare('SELECT * FROM ecommerce_pedido_itens WHERE pedido_id = ?');
            $stmt->execute([$ecommercePedidoId]);
            $itens = $stmt->fetchAll();
            
            $this->pdo->beginTransaction();
            
            foreach ($itens as $item) {
                $productId = (int)$item['product_id'];
                $quantidade = (float)$item['quantidade'];
                
                // Verificar estoque atual
                $stmt = $this->pdo->prepare('SELECT estoque FROM products WHERE id = ? LIMIT 1');
                $stmt->execute([$productId]);
                $produto = $stmt->fetch();
                
                if (!$produto) continue;
                
                $estoqueAtual = (float)($produto['estoque'] ?? 0);
                $novoEstoque = $estoqueAtual - $quantidade;
                
                if (!$allowNegative && $novoEstoque < 0) {
                    $this->pdo->rollBack();
                    error_log("[EcommerceIntegration] Estoque insuficiente para produto $productId");
                    return false;
                }
                
                // Tentar usar stored procedure se existir
                $spOk = false;
                try {
                    $call = $this->pdo->prepare('CALL sp_update_product_stock(?,?,?,?,?,?)');
                    $call->execute([
                        $productId,
                        -$quantidade,
                        'ecommerce_pedido',
                        $ecommercePedidoId,
                        '',
                        $allowNegative ? 1 : 0
                    ]);
                    $spOk = true;
                } catch (\Throwable $e) {
                    $spOk = false;
                }
                
                if (!$spOk) {
                    // Fallback: atualizar estoque diretamente
                    $stmt = $this->pdo->prepare('UPDATE products SET estoque = ? WHERE id = ?');
                    $stmt->execute([$novoEstoque, $productId]);
                    
                    // Registrar movimentação
                    try {
                        $mov = $this->pdo->prepare('INSERT INTO inventory_movements 
                            (product_id, tipo, quantidade, motivo, stock_before, stock_after, origin_type, origin_id, origin_number) 
                            VALUES (?,?,?,?,?,?,?,?,?)');
                        $mov->execute([
                            $productId,
                            'saida_ecommerce',
                            -$quantidade,
                            'Venda E-commerce',
                            $estoqueAtual,
                            $novoEstoque,
                            'ecommerce_pedido',
                            $ecommercePedidoId,
                            ''
                        ]);
                    } catch (\Throwable $e) {
                        // Ignorar se tabela não existir
                    }
                }
            }
            
            $this->pdo->commit();
            return true;
        } catch (\Throwable $e) {
            if ($this->pdo->inTransaction()) {
                $this->pdo->rollBack();
            }
            error_log("[EcommerceIntegration] Erro ao baixar estoque: " . $e->getMessage());
            return false;
        }
    }

    /**
     * Cria conta a receber quando pedido é pago
     */
    public function createContaReceber(int $ecommercePedidoId): ?int {
        try {
            // Buscar pedido
            $stmt = $this->pdo->prepare('SELECT * FROM ecommerce_pedidos WHERE id = ? AND tenant_id = ? LIMIT 1');
            $stmt->execute([$ecommercePedidoId, $this->tenantId]);
            $pedido = $stmt->fetch();
            
            if (!$pedido) {
                return null;
            }
            
            // Buscar cliente
            $clienteData = [
                'nome' => $pedido['cliente_nome'],
                'email' => $pedido['cliente_email'],
                'cpf' => $pedido['cliente_cpf']
            ];
            $enderecoData = json_decode($pedido['endereco_entrega'] ?? '{}', true);
            $clienteId = $this->findOrCreateCliente($clienteData, $enderecoData);
            
            if (!$clienteId) {
                return null;
            }
            
            // Verificar se tabela existe
            $tableExists = $this->pdo->query("SHOW TABLES LIKE 'contas_receber'")->rowCount() > 0;
            if (!$tableExists) {
                return null;
            }
            
            // Criar conta a receber
            $valor = (float)$pedido['total'];
            $dataVencimento = date('Y-m-d', strtotime('+30 days')); // 30 dias após o pedido
            $descricao = "Pedido E-commerce: " . $pedido['numero_pedido'];
            
            $stmt = $this->pdo->prepare('INSERT INTO contas_receber 
                (cliente_id, descricao, valor, data_vencimento, status, origem_tipo, origem_id, documento)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?)');
            
            $stmt->execute([
                $clienteId,
                $descricao,
                $valor,
                $dataVencimento,
                $pedido['payment_status'] === 'pago' ? 'recebido' : 'pendente',
                'ecommerce_pedido',
                $ecommercePedidoId,
                $pedido['numero_pedido']
            ]);
            
            $contaId = (int)$this->pdo->lastInsertId();
            
            // Se já estiver pago, marcar como recebido
            if ($pedido['payment_status'] === 'pago') {
                $stmt = $this->pdo->prepare('UPDATE contas_receber SET 
                    valor_recebido = ?,
                    data_recebimento = NOW(),
                    status = "recebido"
                    WHERE id = ?');
                $stmt->execute([$valor, $contaId]);
            }
            
            AuditLogger::log('create', 'contas_receber', $contaId, [
                'source' => 'ecommerce',
                'ecommerce_pedido_id' => $ecommercePedidoId
            ]);
            
            return $contaId;
        } catch (\Throwable $e) {
            error_log("[EcommerceIntegration] Erro ao criar conta a receber: " . $e->getMessage());
            return null;
        }
    }

    /**
     * Processa pagamento e integra com todos os módulos
     */
    public function processarPagamento(int $ecommercePedidoId, string $paymentStatus, ?string $paymentId = null): bool {
        try {
            $this->pdo->beginTransaction();
            
            // Atualizar status do pedido
            $stmt = $this->pdo->prepare('UPDATE ecommerce_pedidos SET 
                status = ?,
                payment_status = ?,
                payment_id = ?
                WHERE id = ? AND tenant_id = ?');
            
            $status = match($paymentStatus) {
                'approved', 'paid', 'pago' => 'pago',
                'pending', 'pendente' => 'pendente',
                'cancelled', 'cancelado' => 'cancelado',
                default => 'pendente'
            };
            
            $stmt->execute([$status, $paymentStatus, $paymentId, $ecommercePedidoId, $this->tenantId]);
            
            // Se pago, fazer integrações
            if ($status === 'pago') {
                // 1. Criar pedido de venda
                $salesOrderId = $this->createSalesOrderFromEcommerce($ecommercePedidoId);
                
                // 2. Baixar estoque
                $this->baixarEstoque($ecommercePedidoId, false);
                
                // 3. Criar conta a receber
                $this->createContaReceber($ecommercePedidoId);
            }
            
            $this->pdo->commit();
            
            AuditLogger::log('update', 'ecommerce_pedidos', $ecommercePedidoId, [
                'action' => 'processar_pagamento',
                'payment_status' => $paymentStatus,
                'status' => $status
            ]);
            
            return true;
        } catch (\Throwable $e) {
            if ($this->pdo->inTransaction()) {
                $this->pdo->rollBack();
            }
            error_log("[EcommerceIntegration] Erro ao processar pagamento: " . $e->getMessage());
            return false;
        }
    }
}

