<?php

namespace Modules\Integracoes\Instagram\Services;

use PDO;
use Exception;
use Gestoreasy\Core\Tenant\ConnectionManager;

/**
 * Serviço para integração com Instagram Graph API
 */
class InstagramAPIService {
    private PDO $pdo;
    private string $tenantId;
    private string $baseUrl = 'https://graph.facebook.com/v18.0';
    private ?string $accessToken = null;

    public function __construct(string $tenantId) {
        $this->tenantId = $tenantId;
        $this->pdo = ConnectionManager::forTenant($tenantId);
        $config = $this->getConfig(true);
        $this->accessToken = $config['access_token'] ?? $config['long_lived_token'] ?? null;
    }

    /**
     * Obtém configuração do Instagram
     */
    public function getConfig(bool $incluirSecrets = false): array {
        $stmt = $this->pdo->prepare('SELECT * FROM instagram_config WHERE tenant_id = ?');
        $stmt->execute([$this->tenantId]);
        $config = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$config) {
            return [
                'app_id' => '',
                'app_secret' => '',
                'access_token' => null,
                'long_lived_token' => null,
                'instagram_account_id' => null,
                'instagram_business_id' => null,
                'ativo' => false
            ];
        }

        if (!$incluirSecrets) {
            unset($config['app_secret'], $config['access_token'], $config['long_lived_token']);
        }

        return $config;
    }

    /**
     * Atualiza configuração do Instagram
     */
    public function updateConfig(array $dados): void {
        $stmt = $this->pdo->prepare('SELECT id FROM instagram_config WHERE tenant_id = ?');
        $stmt->execute([$this->tenantId]);
        $exists = $stmt->fetch();

        $allowedFields = [
            'app_id', 'app_secret', 'access_token', 'long_lived_token', 'token_expires_at',
            'instagram_account_id', 'instagram_business_id', 'sincronizar_produtos',
            'auto_publicar', '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 instagram_config SET ' . implode(', ', $updates) . ' WHERE tenant_id = ?';
                $stmt = $this->pdo->prepare($sql);
                $stmt->execute($params);
            }
        } else {
            $fields = ['tenant_id'];
            $values = ['?'];
            $params = [$this->tenantId];
            
            foreach ($allowedFields as $field) {
                if (isset($dados[$field])) {
                    $fields[] = $field;
                    $values[] = '?';
                    $params[] = $dados[$field];
                }
            }
            
            $sql = 'INSERT INTO instagram_config (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')';
            $stmt = $this->pdo->prepare($sql);
            $stmt->execute($params);
        }

        // Atualizar access token da instância
        if (isset($dados['access_token']) || isset($dados['long_lived_token'])) {
            $config = $this->getConfig(true);
            $this->accessToken = $config['access_token'] ?? $config['long_lived_token'] ?? null;
        }
    }

    /**
     * Faz requisição à Instagram Graph API
     */
    private function request(string $endpoint, string $method = 'GET', array $data = []): array {
        if (!$this->accessToken) {
            throw new Exception('Access token não configurado');
        }

        $url = $this->baseUrl . '/' . ltrim($endpoint, '/');
        $url .= (strpos($url, '?') !== false ? '&' : '?') . 'access_token=' . urlencode($this->accessToken);

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);

        if ($method === 'POST') {
            curl_setopt($ch, CURLOPT_POST, true);
            if (isset($data['image_url'])) {
                // Para upload de imagem, usar multipart/form-data
                curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
            } else {
                curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
            }
        } elseif ($method === 'DELETE') {
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
        }

        $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 ao Instagram: {$error}");
        }

        $decodedResponse = json_decode($response, true);

        if ($httpCode >= 400) {
            $message = $decodedResponse['error']['message'] ?? 'Erro desconhecido no Instagram';
            throw new Exception("Erro HTTP {$httpCode}: {$message}");
        }

        return $decodedResponse;
    }

    /**
     * Troca código de autorização por access token
     */
    public function trocarCodePorToken(string $code, string $redirectUri): array {
        $config = $this->getConfig(true);
        
        if (empty($config['app_id']) || empty($config['app_secret'])) {
            throw new Exception('App ID e App Secret devem estar configurados');
        }

        // Trocar código por short-lived token
        $url = $this->baseUrl . '/oauth/access_token';
        $params = [
            'client_id' => $config['app_id'],
            'client_secret' => $config['app_secret'],
            'redirect_uri' => $redirectUri,
            'code' => $code
        ];

        $ch = curl_init($url . '?' . http_build_query($params));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);

        $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}");
        }

        if ($httpCode >= 400) {
            $errorData = json_decode($response, true);
            $message = $errorData['error']['message'] ?? "Erro HTTP {$httpCode}";
            throw new Exception($message);
        }

        $tokenData = json_decode($response, true);
        
        if (empty($tokenData['access_token'])) {
            throw new Exception('Access token não recebido');
        }

        $shortLivedToken = $tokenData['access_token'];
        $expiresIn = (int)($tokenData['expires_in'] ?? 3600);

        // Trocar por long-lived token
        $longLivedToken = $this->trocarPorLongLivedToken($shortLivedToken, $config['app_id'], $config['app_secret']);

        // Salvar tokens
        $expiresAt = date('Y-m-d H:i:s', time() + (60 * 24 * 60)); // Long-lived token expira em ~60 dias

        $this->updateConfig([
            'access_token' => $shortLivedToken,
            'long_lived_token' => $longLivedToken,
            'token_expires_at' => $expiresAt
        ]);

        $this->registrarLog('oauth', 'sucesso', 'OAuth autorizado com sucesso', [
            'expires_at' => $expiresAt
        ]);

        return [
            'success' => true,
            'expires_at' => $expiresAt
        ];
    }

    /**
     * Troca short-lived token por long-lived token
     */
    private function trocarPorLongLivedToken(string $shortLivedToken, string $appId, string $appSecret): string {
        $url = $this->baseUrl . '/oauth/access_token';
        $params = [
            'grant_type' => 'fb_exchange_token',
            'client_id' => $appId,
            'client_secret' => $appSecret,
            'fb_exchange_token' => $shortLivedToken
        ];

        $ch = curl_init($url . '?' . http_build_query($params));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);

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

        if ($httpCode >= 400) {
            // Se falhar, retornar o short-lived token
            return $shortLivedToken;
        }

        $tokenData = json_decode($response, true);
        return $tokenData['access_token'] ?? $shortLivedToken;
    }

    /**
     * Sincroniza produtos do ERP para o Instagram Shopping
     */
    public function sincronizarProdutos(): array {
        $config = $this->getConfig();
        if (!$config['ativo'] || !$config['instagram_business_id']) {
            throw new Exception('Integração Instagram desativada ou instagram_business_id não configurado');
        }

        $sincronizados = 0;
        $erros = 0;

        // Buscar produtos do ERP
        $stmt = $this->pdo->prepare('
            SELECT p.id, p.codigo, p.nome, p.descricao, p.preco, p.estoque, p.ativo
            FROM products p
            WHERE p.ativo = 1
            ORDER BY p.nome
        ');
        $stmt->execute();
        $produtos = $stmt->fetchAll(PDO::FETCH_ASSOC);

        foreach ($produtos as $produto) {
            try {
                // Verificar se já existe mapeamento
                $stmt = $this->pdo->prepare('
                    SELECT instagram_product_id FROM instagram_produtos
                    WHERE tenant_id = ? AND product_id = ?
                ');
                $stmt->execute([$this->tenantId, $produto['id']]);
                $mapeamento = $stmt->fetch(PDO::FETCH_ASSOC);

                // Instagram Shopping usa o Facebook Catalog
                // Os produtos devem ser criados no Facebook Catalog primeiro
                // Por enquanto, apenas salvar o mapeamento
                if (!$mapeamento) {
                    $this->salvarMapeamentoProduto($produto['id'], null, null);
                    $this->registrarLog('produto', 'sucesso', "Produto {$produto['id']} preparado para Instagram Shopping", ['product_id' => $produto['id']]);
                }

                $sincronizados++;
            } catch (Exception $e) {
                $erros++;
                $this->registrarLog('produto', 'erro', "Erro ao sincronizar produto {$produto['id']}: " . $e->getMessage(), ['product_id' => $produto['id']]);
            }
        }

        return [
            'sincronizados' => $sincronizados,
            'erros' => $erros
        ];
    }

    /**
     * Salva/atualiza mapeamento de produto
     */
    private function salvarMapeamentoProduto(int $productId, ?string $instagramProductId, ?string $catalogId): void {
        $stmt = $this->pdo->prepare('
            INSERT INTO instagram_produtos (tenant_id, product_id, instagram_product_id, catalog_id, status, sincronizado, ultima_sincronizacao)
            VALUES (?, ?, ?, ?, "active", TRUE, NOW())
            ON DUPLICATE KEY UPDATE
                instagram_product_id = VALUES(instagram_product_id),
                catalog_id = VALUES(catalog_id),
                status = "active",
                sincronizado = TRUE,
                ultima_sincronizacao = NOW()
        ');
        $stmt->execute([$this->tenantId, $productId, $instagramProductId, $catalogId]);
    }

    /**
     * Cria publicação no Instagram
     */
    public function criarPublicacao(array $dados): array {
        $config = $this->getConfig();
        if (!$config['ativo'] || !$config['instagram_account_id']) {
            throw new Exception('Integração Instagram desativada ou instagram_account_id não configurado');
        }

        $tipo = $dados['tipo'] ?? 'photo';
        $legenda = $dados['legenda'] ?? '';
        $urlImagem = $dados['url_imagem'] ?? null;

        if (!$urlImagem) {
            throw new Exception('URL da imagem é obrigatória');
        }

        // Criar container de mídia
        $params = [
            'image_url' => $urlImagem,
            'caption' => $legenda
        ];

        $response = $this->request("{$config['instagram_account_id']}/media", 'POST', $params);
        $creationId = $response['id'] ?? null;

        if (!$creationId) {
            throw new Exception('Falha ao criar container de mídia no Instagram');
        }

        // Publicar mídia
        $publishParams = ['creation_id' => $creationId];
        $publishResponse = $this->request("{$config['instagram_account_id']}/media_publish", 'POST', $publishParams);
        $mediaId = $publishResponse['id'] ?? null;

        if (!$mediaId) {
            throw new Exception('Falha ao publicar no Instagram');
        }

        // Salvar publicação no banco
        $stmt = $this->pdo->prepare('
            INSERT INTO instagram_publicacoes (
                tenant_id, instagram_media_id, product_id, tipo, legenda,
                url_imagem, status, data_publicacao
            ) VALUES (?, ?, ?, ?, ?, ?, ?, NOW())
        ');
        $stmt->execute([
            $this->tenantId,
            $mediaId,
            $dados['product_id'] ?? null,
            $tipo,
            $legenda,
            $urlImagem,
            'published'
        ]);

        $this->registrarLog('publicacao', 'sucesso', "Publicação criada no Instagram", ['media_id' => $mediaId]);

        return [
            'success' => true,
            'media_id' => $mediaId
        ];
    }

    /**
     * Obtém estatísticas de uma publicação
     */
    public function getEstatisticasPublicacao(string $mediaId): array {
        $response = $this->request("{$mediaId}/insights", 'GET', [
            'metric' => 'impressions,reach,likes,comments'
        ]);

        $estatisticas = [];
        foreach ($response['data'] ?? [] as $metric) {
            $estatisticas[$metric['name']] = (int)($metric['values'][0]['value'] ?? 0);
        }

        return [
            'likes' => $estatisticas['likes'] ?? 0,
            'comentarios' => $estatisticas['comments'] ?? 0,
            'alcance' => $estatisticas['reach'] ?? $estatisticas['impressions'] ?? 0
        ];
    }

    /**
     * Processa webhook do Instagram
     */
    public function processarWebhook(array $payload, array $headers): void {
        // Validar assinatura do webhook
        $signature = $headers['X-Hub-Signature-256'] ?? '';
        $config = $this->getConfig(true);
        
        if ($config['webhook_token']) {
            $expectedSignature = 'sha256=' . hash_hmac('sha256', json_encode($payload), $config['webhook_token']);
            if ($signature !== $expectedSignature) {
                throw new Exception('Assinatura do webhook inválida');
            }
        }

        // Processar eventos
        $entry = $payload['entry'][0] ?? null;
        if (!$entry) {
            return;
        }

        $changes = $entry['changes'] ?? [];
        foreach ($changes as $change) {
            $this->processarEvento($change);
        }
    }

    /**
     * Processa evento do webhook
     */
    private function processarEvento(array $change): void {
        $field = $change['field'] ?? '';
        $value = $change['value'] ?? [];

        switch ($field) {
            case 'mentions':
                // Nova menção
                $this->registrarLog('webhook', 'sucesso', 'Nova menção recebida', $change);
                break;
            case 'story_mentions':
                // Menção em story
                $this->registrarLog('webhook', 'sucesso', 'Menção em story recebida', $change);
                break;
            default:
                $this->registrarLog('webhook', 'aviso', "Evento desconhecido: {$field}", $change);
                break;
        }
    }

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

