<?php
namespace Modules\Ecommerce\Controllers;

use Gestoreasy\Core\Http\Request;
use Gestoreasy\Core\Http\Response;
use Gestoreasy\Core\Tenant\ConnectionManager;
use Gestoreasy\Core\Tenant\TenantContext;
use Gestoreasy\Core\Audit\AuditLogger;
use Gestoreasy\Core\Security\Crypto;

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

    // Configurações gerais
    public function getConfig(Request $req): Response {
        $pdo = ConnectionManager::forTenant();
        $tenantId = $this->getTenantId();
        
        $stmt = $pdo->prepare('SELECT * FROM ecommerce_config WHERE tenant_id = ? LIMIT 1');
        $stmt->execute([$tenantId]);
        $config = $stmt->fetch();
        
        if (!$config) {
            // Criar configuração padrão
            $stmt = $pdo->prepare('INSERT INTO ecommerce_config (tenant_id, store_name) VALUES (?, ?)');
            $stmt->execute([$tenantId, 'Minha Loja']);
            $config = ['tenant_id' => $tenantId, 'store_name' => 'Minha Loja', 'enabled' => true];
        }
        
        return Response::json(['data' => $config]);
    }

    public function updateConfig(Request $req): Response {
        $pdo = ConnectionManager::forTenant();
        $tenantId = $this->getTenantId();
        $body = $req->body;
        
        $fields = ['store_name', 'store_description', 'logo_url', 'whatsapp', 'email_contato', 'template_id', 'theme_colors', 'enabled'];
        $updates = [];
        $values = [];
        
        foreach ($fields as $field) {
            if (isset($body[$field])) {
                if ($field === 'theme_colors' && is_array($body[$field])) {
                    $updates[] = "$field = ?";
                    $values[] = json_encode($body[$field]);
                } else {
                    $updates[] = "$field = ?";
                    $values[] = $body[$field];
                }
            }
        }
        
        if (empty($updates)) {
            return new Response(422, ['error' => ['code' => 'no_updates', 'message' => 'Nenhum campo para atualizar']]);
        }
        
        // Verificar se existe
        $stmt = $pdo->prepare('SELECT id FROM ecommerce_config WHERE tenant_id = ? LIMIT 1');
        $stmt->execute([$tenantId]);
        $exists = $stmt->fetch();
        
        if ($exists) {
            $values[] = $tenantId;
            $sql = 'UPDATE ecommerce_config SET ' . implode(', ', $updates) . ' WHERE tenant_id = ?';
        } else {
            $updates[] = 'tenant_id = ?';
            $values[] = $tenantId;
            $sql = 'INSERT INTO ecommerce_config SET ' . implode(', ', $updates);
        }
        
        $stmt = $pdo->prepare($sql);
        $stmt->execute($values);
        
        AuditLogger::log('update', 'ecommerce_config', null, ['tenant_id' => $tenantId]);
        
        return Response::json(['message' => 'Configuração atualizada com sucesso']);
    }

    // Templates
    public function listTemplates(Request $req): Response {
        $pdo = ConnectionManager::forTenant();
        $stmt = $pdo->query('SELECT * FROM ecommerce_templates WHERE enabled = TRUE ORDER BY name');
        $templates = $stmt->fetchAll();
        
        return Response::json(['data' => $templates]);
    }

    public function getTemplate(Request $req): Response {
        $pdo = ConnectionManager::forTenant();
        $templateId = $req->get('params')[0] ?? null;
        
        if (!$templateId) {
            return new Response(422, ['error' => ['code' => 'invalid_id', 'message' => 'ID do template inválido']]);
        }
        
        $stmt = $pdo->prepare('SELECT * FROM ecommerce_templates WHERE code = ? OR id = ? LIMIT 1');
        $stmt->execute([$templateId, $templateId]);
        $template = $stmt->fetch();
        
        if (!$template) {
            return new Response(404, ['error' => ['code' => 'not_found', 'message' => 'Template não encontrado']]);
        }
        
        return Response::json(['data' => $template]);
    }

    public function setTemplate(Request $req): Response {
        $pdo = ConnectionManager::forTenant();
        $tenantId = $this->getTenantId();
        $templateId = $req->body['template_id'] ?? null;
        
        if (!$templateId) {
            return new Response(422, ['error' => ['code' => 'invalid_template', 'message' => 'Template ID é obrigatório']]);
        }
        
        // Verificar se template existe
        $stmt = $pdo->prepare('SELECT id FROM ecommerce_templates WHERE code = ? OR id = ? LIMIT 1');
        $stmt->execute([$templateId, $templateId]);
        if (!$stmt->fetch()) {
            return new Response(404, ['error' => ['code' => 'template_not_found', 'message' => 'Template não encontrado']]);
        }
        
        // Atualizar config
        $stmt = $pdo->prepare('UPDATE ecommerce_config SET template_id = ? WHERE tenant_id = ?');
        $stmt->execute([$templateId, $tenantId]);
        
        AuditLogger::log('update', 'ecommerce_config', null, ['action' => 'set_template', 'template_id' => $templateId]);
        
        return Response::json(['message' => 'Template atualizado com sucesso']);
    }

    // Domínios
    public function listDominios(Request $req): Response {
        $pdo = ConnectionManager::forTenant();
        $tenantId = $this->getTenantId();
        
        $stmt = $pdo->prepare('SELECT * FROM ecommerce_dominios WHERE tenant_id = ? ORDER BY created_at DESC');
        $stmt->execute([$tenantId]);
        $dominios = $stmt->fetchAll();
        
        return Response::json(['data' => $dominios]);
    }

    public function createDominio(Request $req): Response {
        $pdo = ConnectionManager::forTenant();
        $tenantId = $this->getTenantId();
        $body = $req->body;
        
        $dominio = $body['dominio'] ?? '';
        $tipo = $body['tipo'] ?? 'subdominio';
        $subdominio = $body['subdominio'] ?? null;
        
        if (empty($dominio)) {
            return new Response(422, ['error' => ['code' => 'invalid_dominio', 'message' => 'Domínio é obrigatório']]);
        }
        
        if ($tipo === 'subdominio' && empty($subdominio)) {
            $subdominio = $tenantId; // Usar tenant_id como subdomínio padrão
        }
        
        try {
            $stmt = $pdo->prepare('INSERT INTO ecommerce_dominios (tenant_id, dominio, tipo, subdominio) VALUES (?, ?, ?, ?)');
            $stmt->execute([$tenantId, $dominio, $tipo, $subdominio]);
            $id = $pdo->lastInsertId();
            
            AuditLogger::log('create', 'ecommerce_dominios', $id, ['dominio' => $dominio, 'tipo' => $tipo]);
            
            return Response::json(['message' => 'Domínio criado com sucesso', 'id' => $id]);
        } catch (\PDOException $e) {
            if ($e->errorInfo[1] === 1062) { // Duplicate entry
                return new Response(409, ['error' => ['code' => 'duplicate_dominio', 'message' => 'Este domínio já está em uso']]);
            }
            throw $e;
        }
    }

    public function updateDominio(Request $req): Response {
        $pdo = ConnectionManager::forTenant();
        $id = $req->get('params')[0] ?? null;
        $body = $req->body;
        
        if (!$id) {
            return new Response(422, ['error' => ['code' => 'invalid_id', 'message' => 'ID inválido']]);
        }
        
        $updates = [];
        $values = [];
        
        $fields = ['dominio', 'tipo', 'subdominio', 'ssl_enabled', 'verified'];
        foreach ($fields as $field) {
            if (isset($body[$field])) {
                $updates[] = "$field = ?";
                $values[] = $body[$field];
            }
        }
        
        if (empty($updates)) {
            return new Response(422, ['error' => ['code' => 'no_updates', 'message' => 'Nenhum campo para atualizar']]);
        }
        
        $values[] = $id;
        $sql = 'UPDATE ecommerce_dominios SET ' . implode(', ', $updates) . ' WHERE id = ?';
        $stmt = $pdo->prepare($sql);
        $stmt->execute($values);
        
        AuditLogger::log('update', 'ecommerce_dominios', $id, $body);
        
        return Response::json(['message' => 'Domínio atualizado com sucesso']);
    }

    public function deleteDominio(Request $req): Response {
        $pdo = ConnectionManager::forTenant();
        $id = $req->get('params')[0] ?? null;
        
        if (!$id) {
            return new Response(422, ['error' => ['code' => 'invalid_id', 'message' => 'ID inválido']]);
        }
        
        $stmt = $pdo->prepare('DELETE FROM ecommerce_dominios WHERE id = ?');
        $stmt->execute([$id]);
        
        AuditLogger::log('delete', 'ecommerce_dominios', $id);
        
        return Response::json(['message' => 'Domínio removido com sucesso']);
    }

    // Pagamentos
    public function getPagamentos(Request $req): Response {
        $pdo = ConnectionManager::forTenant();
        $tenantId = $this->getTenantId();
        
        $stmt = $pdo->prepare('SELECT provider, enabled, public_key, config FROM ecommerce_pagamentos WHERE tenant_id = ?');
        $stmt->execute([$tenantId]);
        $pagamentos = $stmt->fetchAll();
        
        // Não retornar tokens/secrets
        $result = [];
        foreach ($pagamentos as $p) {
            $result[$p['provider']] = [
                'enabled' => (bool)$p['enabled'],
                'public_key' => $p['public_key'],
                'config' => json_decode($p['config'] ?? '{}', true)
            ];
        }
        
        return Response::json(['data' => $result]);
    }

    public function updateMercadoPago(Request $req): Response {
        return $this->updatePagamentoProvider('mercadopago', $req);
    }

    public function updatePagBank(Request $req): Response {
        return $this->updatePagamentoProvider('pagbank', $req);
    }

    public function updateOutrosPagamentos(Request $req): Response {
        $body = $req->body;
        $provider = $body['provider'] ?? null;
        
        if (!$provider) {
            return new Response(422, ['error' => ['code' => 'invalid_provider', 'message' => 'Provider é obrigatório']]);
        }
        
        return $this->updatePagamentoProvider($provider, $req);
    }

    private function updatePagamentoProvider(string $provider, Request $req): Response {
        $pdo = ConnectionManager::forTenant();
        $tenantId = $this->getTenantId();
        $body = $req->body;
        
        $enabled = isset($body['enabled']) ? (bool)$body['enabled'] : false;
        $publicKey = $body['public_key'] ?? null;
        $accessToken = $body['access_token'] ?? null;
        $secretKey = $body['secret_key'] ?? null;
        $config = $body['config'] ?? [];
        
        // Criptografar tokens/secrets
        $encryptedToken = $accessToken ? Crypto::encrypt($accessToken) : null;
        $encryptedSecret = $secretKey ? Crypto::encrypt($secretKey) : null;
        
        // Verificar se existe
        $stmt = $pdo->prepare('SELECT id FROM ecommerce_pagamentos WHERE tenant_id = ? AND provider = ? LIMIT 1');
        $stmt->execute([$tenantId, $provider]);
        $exists = $stmt->fetch();
        
        if ($exists) {
            $updates = ['enabled = ?', 'public_key = ?', 'config = ?'];
            $values = [$enabled, $publicKey, json_encode($config)];
            
            if ($encryptedToken) {
                $updates[] = 'access_token = ?';
                $values[] = $encryptedToken;
            }
            if ($encryptedSecret) {
                $updates[] = 'secret_key = ?';
                $values[] = $encryptedSecret;
            }
            
            $values[] = $tenantId;
            $values[] = $provider;
            $sql = 'UPDATE ecommerce_pagamentos SET ' . implode(', ', $updates) . ' WHERE tenant_id = ? AND provider = ?';
        } else {
            $sql = 'INSERT INTO ecommerce_pagamentos (tenant_id, provider, enabled, public_key, access_token, secret_key, config) VALUES (?, ?, ?, ?, ?, ?, ?)';
            $values = [$tenantId, $provider, $enabled, $publicKey, $encryptedToken, $encryptedSecret, json_encode($config)];
        }
        
        $stmt = $pdo->prepare($sql);
        $stmt->execute($values);
        
        AuditLogger::log('update', 'ecommerce_pagamentos', null, ['provider' => $provider, 'enabled' => $enabled]);
        
        return Response::json(['message' => 'Configuração de pagamento atualizada com sucesso']);
    }

    // Produtos
    public function listProdutos(Request $req): Response {
        $pdo = ConnectionManager::forTenant();
        $tenantId = $this->getTenantId();
        
        $page = (int)($req->get('page') ?? 1);
        $perPage = (int)($req->get('per_page') ?? 20);
        $offset = ($page - 1) * $perPage;
        
        // Buscar produtos com informações do e-commerce e estoque
        $sql = 'SELECT 
            p.id, p.codigo, p.nome, p.preco, p.estoque,
            ep.visible, ep.featured, ep.custom_price, ep.seo_title, ep.seo_description,
            COALESCE(ep.custom_price, p.preco) as preco_ecommerce
        FROM products p
        LEFT JOIN ecommerce_produtos ep ON ep.product_id = p.id AND ep.tenant_id = ?
        ORDER BY ep.order_index ASC, p.created_at DESC
        LIMIT ? OFFSET ?';
        
        $stmt = $pdo->prepare($sql);
        $stmt->execute([$tenantId, $perPage, $offset]);
        $produtos = $stmt->fetchAll();
        
        // Contar total
        $stmt = $pdo->query('SELECT COUNT(*) as total FROM products');
        $total = (int)$stmt->fetch()['total'];
        
        return Response::json([
            'data' => $produtos,
            'page' => $page,
            'per_page' => $perPage,
            'total' => $total,
            'total_pages' => ceil($total / $perPage)
        ]);
    }

    public function toggleProdutoVisibilidade(Request $req): Response {
        $pdo = ConnectionManager::forTenant();
        $tenantId = $this->getTenantId();
        $productId = $req->get('params')[0] ?? null;
        $visible = $req->body['visible'] ?? true;
        
        if (!$productId) {
            return new Response(422, ['error' => ['code' => 'invalid_id', 'message' => 'ID do produto inválido']]);
        }
        
        // Verificar se produto existe
        $stmt = $pdo->prepare('SELECT id FROM products WHERE id = ? LIMIT 1');
        $stmt->execute([$productId]);
        if (!$stmt->fetch()) {
            return new Response(404, ['error' => ['code' => 'product_not_found', 'message' => 'Produto não encontrado']]);
        }
        
        // Verificar se já existe registro
        $stmt = $pdo->prepare('SELECT id FROM ecommerce_produtos WHERE product_id = ? AND tenant_id = ? LIMIT 1');
        $stmt->execute([$productId, $tenantId]);
        $exists = $stmt->fetch();
        
        if ($exists) {
            $stmt = $pdo->prepare('UPDATE ecommerce_produtos SET visible = ? WHERE product_id = ? AND tenant_id = ?');
            $stmt->execute([$visible, $productId, $tenantId]);
        } else {
            $stmt = $pdo->prepare('INSERT INTO ecommerce_produtos (product_id, tenant_id, visible) VALUES (?, ?, ?)');
            $stmt->execute([$productId, $tenantId, $visible]);
        }
        
        AuditLogger::log('update', 'ecommerce_produtos', $productId, ['visible' => $visible]);
        
        return Response::json(['message' => 'Visibilidade do produto atualizada']);
    }

    public function sincronizarProdutos(Request $req): Response {
        $pdo = ConnectionManager::forTenant();
        $tenantId = $this->getTenantId();
        
        // Buscar todos os produtos
        $stmt = $pdo->query('SELECT id FROM products');
        $produtos = $stmt->fetchAll();
        
        $sincronizados = 0;
        foreach ($produtos as $produto) {
            // Verificar se já existe
            $stmt = $pdo->prepare('SELECT id FROM ecommerce_produtos WHERE product_id = ? AND tenant_id = ? LIMIT 1');
            $stmt->execute([$produto['id'], $tenantId]);
            
            if (!$stmt->fetch()) {
                // Criar registro padrão (visible = true)
                $stmt = $pdo->prepare('INSERT INTO ecommerce_produtos (product_id, tenant_id, visible) VALUES (?, ?, TRUE)');
                $stmt->execute([$produto['id'], $tenantId]);
                $sincronizados++;
            }
        }
        
        AuditLogger::log('update', 'ecommerce_produtos', null, ['action' => 'sync', 'sincronizados' => $sincronizados]);
        
        return Response::json(['message' => "Sincronização concluída. $sincronizados produtos sincronizados."]);
    }

    // Calculadora de Frete
    public function calcularFrete(Request $req): Response {
        $body = $req->body;
        $cepDestino = preg_replace('/\D/', '', $body['cep'] ?? '');
        $produtos = $body['produtos'] ?? []; // Array de {id, quantidade}
        
        if (empty($cepDestino) || strlen($cepDestino) !== 8) {
            return new Response(422, ['error' => ['code' => 'invalid_cep', 'message' => 'CEP inválido']]);
        }
        
        if (empty($produtos)) {
            return new Response(422, ['error' => ['code' => 'no_products', 'message' => 'Nenhum produto informado']]);
        }
        
        $pdo = ConnectionManager::forTenant();
        $tenantId = $this->getTenantId();
        
        // Buscar configuração de frete
        $stmt = $pdo->prepare('SELECT * FROM ecommerce_frete_config WHERE tenant_id = ? AND enabled = TRUE LIMIT 1');
        $stmt->execute([$tenantId]);
        $freteConfig = $stmt->fetch();
        
        if (!$freteConfig) {
            return new Response(404, ['error' => ['code' => 'frete_not_configured', 'message' => 'Configuração de frete não encontrada']]);
        }
        
        $cepOrigem = preg_replace('/\D/', '', $freteConfig['cep_origem']);
        $provider = $freteConfig['provider'];
        $config = json_decode($freteConfig['config'] ?? '{}', true);
        
        // Calcular peso e dimensões totais
        $pesoTotal = 0;
        $valorTotal = 0;
        
        foreach ($produtos as $item) {
            $stmt = $pdo->prepare('SELECT preco, peso, altura, largura, comprimento FROM products WHERE id = ? LIMIT 1');
            $stmt->execute([$item['id']]);
            $produto = $stmt->fetch();
            
            if ($produto) {
                $quantidade = (int)($item['quantidade'] ?? 1);
                $pesoTotal += (float)($produto['peso'] ?? 0.3) * $quantidade; // Default 300g
                $valorTotal += (float)$produto['preco'] * $quantidade;
            }
        }
        
        // Calcular frete usando o provider
        $opcoes = $this->calcularFreteProvider($provider, $cepOrigem, $cepDestino, $pesoTotal, $config);
        
        return Response::json(['data' => $opcoes]);
    }

    private function calcularFreteProvider(string $provider, string $cepOrigem, string $cepDestino, float $peso, array $config): array {
        switch ($provider) {
            case 'correios':
                return $this->calcularFreteCorreios($cepOrigem, $cepDestino, $peso, $config);
            case 'melhor-envio':
                return $this->calcularFreteMelhorEnvio($cepOrigem, $cepDestino, $peso, $config);
            case 'custom':
                return $this->calcularFreteCustom($peso, $config);
            default:
                return [];
        }
    }

    private function calcularFreteCorreios(string $cepOrigem, string $cepDestino, float $peso, array $config): array {
        // Implementação básica - pode ser expandida com API dos Correios
        $servicos = $config['servicos'] ?? ['PAC', 'SEDEX'];
        $opcoes = [];
        
        foreach ($servicos as $servico) {
            // Valores estimados (deve ser substituído por cálculo real via API)
            $preco = match($servico) {
                'PAC' => max(10.0, $peso * 2.5),
                'SEDEX' => max(15.0, $peso * 5.0),
                default => $peso * 3.0
            };
            
            $prazo = match($servico) {
                'PAC' => 10,
                'SEDEX' => 5,
                default => 8
            };
            
            $opcoes[] = [
                'servico' => $servico,
                'preco' => round($preco, 2),
                'prazo' => $prazo,
                'provider' => 'correios'
            ];
        }
        
        return $opcoes;
    }

    private function calcularFreteMelhorEnvio(string $cepOrigem, string $cepDestino, float $peso, array $config): array {
        // Placeholder - requer integração com API do Melhor Envio
        return [
            [
                'servico' => 'Melhor Envio',
                'preco' => round($peso * 3.0, 2),
                'prazo' => 7,
                'provider' => 'melhor-envio'
            ]
        ];
    }

    private function calcularFreteCustom(float $peso, array $config): array {
        $tabela = $config['tabela'] ?? [];
        $opcoes = [];
        
        foreach ($tabela as $faixa) {
            if ($peso >= $faixa['peso_min'] && $peso <= ($faixa['peso_max'] ?? 999)) {
                $opcoes[] = [
                    'servico' => $faixa['nome'] ?? 'Frete',
                    'preco' => (float)($faixa['preco'] ?? 0),
                    'prazo' => (int)($faixa['prazo'] ?? 7),
                    'provider' => 'custom'
                ];
            }
        }
        
        return $opcoes;
    }
}

