<?php

namespace Modules\Integracoes\TikTokSeller\Services;

use PDO;
use Exception;

/**
 * Serviço para integração com API do TikTok Seller
 */
class TikTokSellerAPIService {
    private PDO $pdo;
    private string $tenantId;
    private string $baseUrl = 'https://open-api.tiktokglobalshop.com';

    public function __construct(string $tenantId) {
        $this->tenantId = $tenantId;
        $this->pdo = \Gestoreasy\Core\Tenant\ConnectionManager::forTenant($tenantId);
    }

    public function getConfig(): array {
        $stmt = $this->pdo->prepare('SELECT * FROM tiktok_config WHERE tenant_id = ?');
        $stmt->execute([$this->tenantId]);
        $config = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$config) {
            return [
                'ativo' => false,
                'sincronizar_produtos' => false,
                'sincronizar_pedidos' => false,
                'sincronizar_estoque' => false
            ];
        }

        return $config;
    }

    public function updateConfig(array $dados): void {
        $stmt = $this->pdo->prepare('SELECT id FROM tiktok_config WHERE tenant_id = ?');
        $stmt->execute([$this->tenantId]);
        $exists = $stmt->fetch();

        $allowedFields = [
            'app_id', 'app_secret', 'access_token', 'refresh_token', 'token_expires_at',
            'seller_id', 'shop_id', 'sincronizar_produtos', 'sincronizar_pedidos',
            'sincronizar_estoque', 'intervalo_sincronizacao_minutos', 'webhook_url',
            'webhook_token', 'ativo'
        ];

        if ($exists) {
            $updates = [];
            $params = [];
            foreach ($allowedFields as $field) {
                if (isset($dados[$field])) {
                    $updates[] = "{$field} = ?";
                    $params[] = $dados[$field];
                }
            }
            if (!empty($updates)) {
                $params[] = $this->tenantId;
                $sql = 'UPDATE tiktok_config SET ' . implode(', ', $updates) . ' WHERE tenant_id = ?';
                $stmt = $this->pdo->prepare($sql);
                $stmt->execute($params);
            }
        } else {
            $fields = [];
            $values = [];
            $params = [];
            foreach ($allowedFields as $field) {
                if (isset($dados[$field])) {
                    $fields[] = $field;
                    $values[] = '?';
                    $params[] = $dados[$field];
                }
            }
            if (!empty($fields)) {
                $params[] = $this->tenantId;
                $sql = 'INSERT INTO tiktok_config (tenant_id, ' . implode(', ', $fields) . ') VALUES (?, ' . implode(', ', $values) . ')';
                $stmt = $this->pdo->prepare($sql);
                $stmt->execute($params);
            }
        }
    }

    private function request(string $endpoint, string $method = 'GET', array $data = []): array {
        $config = $this->getConfig();
        
        if (empty($config['access_token'])) {
            throw new Exception('Access token não configurado');
        }

        $url = $this->baseUrl . $endpoint;
        $ch = curl_init($url);

        $headers = [
            'Authorization: Bearer ' . $config['access_token'],
            'Content-Type: application/json'
        ];

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_SSL_VERIFYPEER => true
        ]);

        if (!empty($data) && in_array($method, ['POST', 'PUT', 'PATCH'])) {
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        }

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);

        if ($error) {
            throw new Exception("Erro na requisição: {$error}");
        }

        $data = json_decode($response, true);
        if ($httpCode >= 400) {
            throw new Exception($data['message'] ?? 'Erro na API do TikTok');
        }

        return $data;
    }

    public function handleOAuthCallback(string $code): array {
        $config = $this->getConfig();
        
        $url = 'https://auth.tiktok-shops.com/api/v2/token/get';
        $data = [
            'app_key' => $config['app_id'],
            'app_secret' => $config['app_secret'],
            'auth_code' => $code,
            'grant_type' => 'authorized_code'
        ];

        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => json_encode($data),
            CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
            CURLOPT_SSL_VERIFYPEER => true
        ]);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($httpCode !== 200) {
            throw new Exception('Erro ao obter access token');
        }

        $result = json_decode($response, true);
        
        $this->updateConfig([
            'access_token' => $result['data']['access_token'],
            'refresh_token' => $result['data']['refresh_token'],
            'token_expires_at' => date('Y-m-d H:i:s', time() + $result['data']['expires_in']),
            'seller_id' => $result['data']['seller_id'] ?? null,
            'shop_id' => $result['data']['shop_id'] ?? null
        ]);

        return ['success' => true];
    }

    public function sincronizarProdutos(): array {
        $config = $this->getConfig();
        if (!$config['sincronizar_produtos']) {
            throw new Exception('Sincronização de produtos desativada');
        }

        // Buscar produtos do TikTok
        $response = $this->request('/product/202309/products/search', 'POST', [
            'page_size' => 100
        ]);

        $produtos = $response['data']['products'] ?? [];
        $sincronizados = 0;

        foreach ($produtos as $produto) {
            // Mapear para produtos do ERP
            $stmt = $this->pdo->prepare('
                SELECT id FROM products 
                WHERE tenant_id = ? AND codigo = ? OR sku = ?
                LIMIT 1
            ');
            $stmt->execute([$this->tenantId, $produto['sku'], $produto['sku']]);
            $product = $stmt->fetch(PDO::FETCH_ASSOC);

            if ($product) {
                $stmt = $this->pdo->prepare('
                    INSERT INTO tiktok_produtos (tenant_id, product_id, tiktok_product_id, tiktok_sku, status, sincronizado, ultima_sincronizacao)
                    VALUES (?, ?, ?, ?, ?, 1, NOW())
                    ON DUPLICATE KEY UPDATE
                        tiktok_product_id = VALUES(tiktok_product_id),
                        status = VALUES(status),
                        sincronizado = 1,
                        ultima_sincronizacao = NOW()
                ');
                $stmt->execute([
                    $this->tenantId,
                    $product['id'],
                    $produto['id'],
                    $produto['sku'],
                    $produto['sale_status'] ?? 'draft'
                ]);
                $sincronizados++;
            }
        }

        $this->log('produto', 'sucesso', "Sincronizados {$sincronizados} produtos");

        return ['sincronizados' => $sincronizados, 'total' => count($produtos)];
    }

    public function publicarProduto(int $productId, array $dados): array {
        $stmt = $this->pdo->prepare('SELECT * FROM products WHERE id = ? AND tenant_id = ?');
        $stmt->execute([$productId, $this->tenantId]);
        $product = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$product) {
            throw new Exception('Produto não encontrado');
        }

        // Preparar dados para API do TikTok
        $payload = [
            'title' => $product['nome'],
            'description' => $product['descricao'] ?? '',
            'sku' => $product['codigo'],
            'price' => [
                'amount' => (string)($product['preco'] * 100), // Em centavos
                'currency' => 'BRL'
            ],
            'stock' => (int)$product['estoque']
        ];

        $response = $this->request('/product/202309/products', 'POST', $payload);

        // Salvar mapeamento
        $stmt = $this->pdo->prepare('
            INSERT INTO tiktok_produtos (tenant_id, product_id, tiktok_product_id, tiktok_sku, status, sincronizado, ultima_sincronizacao)
            VALUES (?, ?, ?, ?, ?, 1, NOW())
            ON DUPLICATE KEY UPDATE
                tiktok_product_id = VALUES(tiktok_product_id),
                status = VALUES(status),
                sincronizado = 1,
                ultima_sincronizacao = NOW()
        ');
        $stmt->execute([
            $this->tenantId,
            $productId,
            $response['data']['product_id'],
            $product['codigo'],
            'active'
        ]);

        return ['success' => true, 'tiktok_product_id' => $response['data']['product_id']];
    }

    public function sincronizarPedidos(): array {
        $config = $this->getConfig();
        if (!$config['sincronizar_pedidos']) {
            throw new Exception('Sincronização de pedidos desativada');
        }

        $response = $this->request('/order/202309/orders/search', 'POST', [
            'page_size' => 100,
            'order_status' => 'UNPAID,PROCESSING,SHIPPED'
        ]);

        $pedidos = $response['data']['order_list'] ?? [];
        $sincronizados = 0;

        foreach ($pedidos as $pedido) {
            $stmt = $this->pdo->prepare('
                INSERT INTO tiktok_pedidos (tenant_id, tiktok_order_id, status_tiktok, total, currency, buyer_id, dados_json, sincronizado)
                VALUES (?, ?, ?, ?, ?, ?, ?, 1)
                ON DUPLICATE KEY UPDATE
                    status_tiktok = VALUES(status_tiktok),
                    total = VALUES(total),
                    dados_json = VALUES(dados_json),
                    sincronizado = 1,
                    updated_at = NOW()
            ');
            $stmt->execute([
                $this->tenantId,
                $pedido['order_id'],
                $pedido['order_status'],
                $pedido['total_amount']['amount'] / 100,
                $pedido['total_amount']['currency'] ?? 'BRL',
                $pedido['buyer_uid'] ?? null,
                json_encode($pedido)
            ]);
            $sincronizados++;
        }

        $this->log('pedido', 'sucesso', "Sincronizados {$sincronizados} pedidos");

        return ['sincronizados' => $sincronizados, 'total' => count($pedidos)];
    }

    public function importarPedido(string $tiktokOrderId): array {
        $stmt = $this->pdo->prepare('SELECT * FROM tiktok_pedidos WHERE tiktok_order_id = ? AND tenant_id = ?');
        $stmt->execute([$tiktokOrderId, $this->tenantId]);
        $pedido = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$pedido) {
            throw new Exception('Pedido não encontrado');
        }

        if ($pedido['importado']) {
            throw new Exception('Pedido já foi importado');
        }

        $dados = json_decode($pedido['dados_json'], true);

        // Criar pedido no ERP (sales_orders)
        try {
            $this->pdo->beginTransaction();

            // 1. Buscar ou criar cliente
            $clienteId = $this->buscarOuCriarCliente($dados);

            // 2. Gerar número do pedido
            $numero = $this->gerarNumeroPedido();

            // 3. Criar pedido
            $stmt = $this->pdo->prepare('
                INSERT INTO sales_orders (numero, cliente_id, valor_total, status, observacoes)
                VALUES (?, ?, ?, ?, ?)
            ');
            $observacoes = "Pedido importado do TikTok - Order ID: {$pedido['tiktok_order_id']}";
            $stmt->execute([
                $numero,
                $clienteId,
                $pedido['total'],
                'aberto',
                $observacoes
            ]);
            $salesOrderId = (int)$this->pdo->lastInsertId();

            // 4. Criar itens do pedido
            if (isset($dados['items']) && is_array($dados['items'])) {
                $this->criarItensPedido($salesOrderId, $dados['items']);
            }

            // 5. Atualizar tiktok_pedidos com sales_order_id
            $stmt = $this->pdo->prepare('
                UPDATE tiktok_pedidos 
                SET sales_order_id = ?, importado = 1 
                WHERE id = ?
            ');
            $stmt->execute([$salesOrderId, $pedido['id']]);

            $this->pdo->commit();

            // Log de sucesso
            $this->log('pedido', 'sucesso', "Pedido {$pedido['tiktok_order_id']} importado como pedido #{$numero}");

            return [
                'success' => true,
                'message' => 'Pedido importado com sucesso',
                'sales_order_id' => $salesOrderId,
                'numero' => $numero
            ];
        } catch (\Exception $e) {
            if ($this->pdo->inTransaction()) {
                $this->pdo->rollBack();
            }
            $this->log('pedido', 'erro', "Erro ao importar pedido {$pedido['tiktok_order_id']}: " . $e->getMessage());
            throw $e;
        }
    }

    public function sincronizarEstoque(int $productId): array {
        $stmt = $this->pdo->prepare('SELECT * FROM products WHERE id = ? AND tenant_id = ?');
        $stmt->execute([$productId, $this->tenantId]);
        $product = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$product) {
            throw new Exception('Produto não encontrado');
        }

        $stmt = $this->pdo->prepare('SELECT tiktok_product_id FROM tiktok_produtos WHERE product_id = ? AND tenant_id = ?');
        $stmt->execute([$productId, $this->tenantId]);
        $tiktokProduct = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$tiktokProduct) {
            throw new Exception('Produto não está publicado no TikTok');
        }

        $response = $this->request('/product/202309/products/' . $tiktokProduct['tiktok_product_id'] . '/stock', 'PUT', [
            'stock' => (int)$product['estoque']
        ]);

        $this->log('estoque', 'sucesso', "Estoque sincronizado para produto {$productId}");

        return ['success' => true];
    }

    /**
     * Busca ou cria um cliente baseado nos dados do pedido TikTok
     */
    private function buscarOuCriarCliente(array $dados): int {
        // Tentar buscar por email ou nome
        $email = $dados['buyer']['email'] ?? null;
        $nome = $dados['buyer']['name'] ?? $dados['buyer_name'] ?? null;
        $telefone = $dados['buyer']['phone'] ?? null;

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

        // Buscar por nome (se não encontrou por email)
        if ($nome) {
            $stmt = $this->pdo->prepare('SELECT id FROM clients WHERE nome = ? OR razao_social = ? LIMIT 1');
            $stmt->execute([$nome, $nome]);
            $cliente = $stmt->fetch(PDO::FETCH_ASSOC);
            if ($cliente) {
                return (int)$cliente['id'];
            }
        }

        // Criar novo cliente
        $tipo = 'PF'; // TikTok geralmente é pessoa física
        $nomeFantasia = $nome ?: 'Cliente TikTok';
        $razaoSocial = $nome ?: 'Cliente TikTok';
        $cpf = $dados['buyer']['cpf'] ?? null;
        $cnpj = $dados['buyer']['cnpj'] ?? null;

        // Se tem CNPJ, é PJ
        if ($cnpj) {
            $tipo = 'PJ';
        }

        // Endereço do pedido
        $endereco = $dados['shipping_address'] ?? [];
        $logradouro = $endereco['street_address'] ?? $endereco['address_line1'] ?? '';
        $numero = $endereco['street_number'] ?? $endereco['address_line2'] ?? '';
        $bairro = $endereco['district'] ?? '';
        $cidade = $endereco['city'] ?? '';
        $estado = $endereco['state'] ?? '';
        $cep = $endereco['zipcode'] ?? $endereco['postal_code'] ?? '';

        // Criar cliente (verificar se tabela tem tenant_id)
        try {
            // Tentar inserir com tenant_id primeiro
            $stmt = $this->pdo->prepare('
                INSERT INTO clients (
                    nome, nome_fantasia, razao_social, tipo, cpf, cnpj, 
                    email, telefone_celular, inativo, tenant_id
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0, ?)
            ');
            $stmt->execute([
                $nomeFantasia,
                $nomeFantasia,
                $razaoSocial,
                $tipo,
                $cpf,
                $cnpj,
                $email,
                $telefone,
                $this->tenantId
            ]);
        } catch (\Exception $e) {
            // Se falhar, tentar sem tenant_id (multi-tenancy pode ser por banco)
            $stmt = $this->pdo->prepare('
                INSERT INTO clients (
                    nome, nome_fantasia, razao_social, tipo, cpf, cnpj, 
                    email, telefone_celular, inativo
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0)
            ');
            $stmt->execute([
                $nomeFantasia,
                $nomeFantasia,
                $razaoSocial,
                $tipo,
                $cpf,
                $cnpj,
                $email,
                $telefone
            ]);
        }
        $clienteId = (int)$this->pdo->lastInsertId();

        // Criar endereço do cliente
        if ($logradouro && $cidade && $estado) {
            try {
                $addrStmt = $this->pdo->prepare('
                    INSERT INTO client_addresses (
                        client_id, tipo, logradouro, numero, complemento, 
                        bairro, cidade, estado, cep
                    ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
                ');
                $addrStmt->execute([
                    $clienteId,
                    'principal',
                    $logradouro,
                    $numero,
                    '',
                    $bairro,
                    $cidade,
                    $estado,
                    $cep
                ]);
            } catch (\Exception $e) {
                // Ignorar erro de endereço, não é crítico
            }
        }

        return $clienteId;
    }

    /**
     * Gera número sequencial para o pedido
     */
    private function gerarNumeroPedido(): string {
        try {
            $stmt = $this->pdo->query("
                SELECT MAX(CAST(SUBSTRING(numero, 4) AS UNSIGNED)) AS max_seq 
                FROM sales_orders 
                WHERE numero LIKE 'PD-%'
            ");
            $row = $stmt->fetch(PDO::FETCH_ASSOC);
            $next = ((int)($row['max_seq'] ?? 0)) + 1;
            return 'PD-' . str_pad((string)$next, 10, '0', STR_PAD_LEFT);
        } catch (\Exception $e) {
            // Fallback: usar timestamp
            return 'PD-TK-' . time();
        }
    }

    /**
     * Cria itens do pedido no ERP
     */
    private function criarItensPedido(int $salesOrderId, array $items): void {
        $stmt = $this->pdo->prepare('
            INSERT INTO sales_order_items (
                order_id, product_id, quantidade, preco, total
            ) VALUES (?, ?, ?, ?, ?)
        ');

        foreach ($items as $item) {
            // Buscar produto por SKU do TikTok
            $tiktokSku = $item['sku'] ?? $item['product_sku'] ?? null;
            $productId = null;

            if ($tiktokSku) {
                // Buscar produto mapeado
                $prodStmt = $this->pdo->prepare('
                    SELECT product_id 
                    FROM tiktok_produtos 
                    WHERE tiktok_sku = ? AND tenant_id = ?
                    LIMIT 1
                ');
                $prodStmt->execute([$tiktokSku, $this->tenantId]);
                $prod = $prodStmt->fetch(PDO::FETCH_ASSOC);
                if ($prod) {
                    $productId = (int)$prod['product_id'];
                }
            }

            // Se não encontrou por SKU, tentar por ID do TikTok
            if (!$productId && isset($item['product_id'])) {
                $prodStmt = $this->pdo->prepare('
                    SELECT product_id 
                    FROM tiktok_produtos 
                    WHERE tiktok_product_id = ? AND tenant_id = ?
                    LIMIT 1
                ');
                $prodStmt->execute([$item['product_id'], $this->tenantId]);
                $prod = $prodStmt->fetch(PDO::FETCH_ASSOC);
                if ($prod) {
                    $productId = (int)$prod['product_id'];
                }
            }

            // Se ainda não encontrou, criar produto genérico ou usar ID 0
            if (!$productId) {
                // Criar produto genérico temporário
                $productId = $this->criarProdutoGenerico($item);
            }

            $quantidade = (float)($item['quantity'] ?? $item['qty'] ?? 1);
            $preco = (float)($item['price'] ?? $item['unit_price'] ?? 0);
            $total = $quantidade * $preco;

            $stmt->execute([
                $salesOrderId,
                $productId,
                $quantidade,
                $preco,
                $total
            ]);
        }
    }

    /**
     * Cria produto genérico quando não encontra mapeamento
     */
    private function criarProdutoGenerico(array $item): int {
        $nome = $item['product_name'] ?? $item['title'] ?? 'Produto TikTok';
        $sku = $item['sku'] ?? $item['product_sku'] ?? 'TK-' . time();
        $preco = (float)($item['price'] ?? $item['unit_price'] ?? 0);

        // Criar produto (verificar se tabela tem tenant_id)
        try {
            $stmt = $this->pdo->prepare('
                INSERT INTO products (
                    codigo, nome, preco, estoque, ativo, tenant_id
                ) VALUES (?, ?, ?, 0, 1, ?)
            ');
            $stmt->execute([$sku, $nome, $preco, $this->tenantId]);
        } catch (\Exception $e) {
            // Se falhar, tentar sem tenant_id
            $stmt = $this->pdo->prepare('
                INSERT INTO products (
                    codigo, nome, preco, estoque, ativo
                ) VALUES (?, ?, ?, 0, 1)
            ');
            $stmt->execute([$sku, $nome, $preco]);
        }
        
        return (int)$this->pdo->lastInsertId();
    }

    public function processarWebhook(array $dados): void {
        $eventType = $dados['event_type'] ?? '';
        $orderId = $dados['order_id'] ?? null;

        if ($eventType === 'ORDER_STATUS_CHANGED' && $orderId) {
            // Buscar pedido atualizado
            $response = $this->request('/order/202309/orders/' . $orderId);
            $pedido = $response['data'] ?? null;

            if ($pedido) {
                $stmt = $this->pdo->prepare('
                    UPDATE tiktok_pedidos 
                    SET status_tiktok = ?, dados_json = ?, updated_at = NOW()
                    WHERE tiktok_order_id = ? AND tenant_id = ?
                ');
                $stmt->execute([
                    $pedido['order_status'],
                    json_encode($pedido),
                    $orderId,
                    $this->tenantId
                ]);
            }
        }

        $this->log('webhook', 'sucesso', "Webhook processado: {$eventType}");
    }

    private function log(string $tipo, string $status, string $mensagem, array $detalhes = []): void {
        $stmt = $this->pdo->prepare('
            INSERT INTO tiktok_logs (tenant_id, tipo, status, mensagem, detalhes_json)
            VALUES (?, ?, ?, ?, ?)
        ');
        $stmt->execute([
            $this->tenantId,
            $tipo,
            $status,
            $mensagem,
            json_encode($detalhes)
        ]);
    }
}

