<?php
namespace Modules\GestorY\Services;

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

class YamahaScraperService {
    private PDO $pdo;
    private string $tenantId;
    private string $baseUrl = 'https://ypec-sss.yamaha-motor.co.jp/ypec/ypec/b2c/html5/app/pt_BR/parts-search/';
    private int $timeout = 30;
    private string $userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36';

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

    /**
     * Pesquisa peças no catálogo Yamaha
     */
    public function pesquisarPecas(string $termo, ?string $modelo = null, ?string $ano = null): array {
        try {
            // Verificar se deve usar API oficial
            $stmt = $this->pdo->prepare('SELECT usar_api_oficial, api_key, api_base_url FROM gestory_config WHERE tenant_id = ? LIMIT 1');
            $stmt->execute([$this->tenantId]);
            $config = $stmt->fetch();
            
            if ($config && !empty($config['usar_api_oficial']) && !empty($config['api_key'])) {
                // Usar API oficial
                $apiService = new \Modules\GestorY\Services\ApiMigrationService();
                return $apiService->pesquisarViaApi($termo, $modelo, $ano);
            }
            
            // Verificar se deve usar browser scraper
            $stmt = $this->pdo->prepare('SELECT scraper_type FROM gestory_config WHERE tenant_id = ? LIMIT 1');
            $stmt->execute([$this->tenantId]);
            $scraperConfig = $stmt->fetch();
            $scraperType = $scraperConfig['scraper_type'] ?? 'curl';
            
            if ($scraperType === 'puppeteer' || $scraperType === 'selenium') {
                // Usar browser scraper
                $browserService = new \Modules\GestorY\Services\BrowserScraperService();
                if ($scraperType === 'puppeteer') {
                    return $browserService->pesquisarComPuppeteer($termo, $modelo, $ano);
                } else {
                    return $browserService->pesquisarComSelenium($termo, $modelo, $ano);
                }
            }
            
            // Verificar cache primeiro
            $cacheKey = md5("pesquisa_{$termo}_{$modelo}_{$ano}");
            $cached = $this->getCache($cacheKey);
            if ($cached !== null) {
                $this->log('pesquisa', 'Cache hit', ['termo' => $termo, 'modelo' => $modelo, 'ano' => $ano], true);
                return $cached;
            }

            // Construir URL de pesquisa
            $params = [
                'searchTerm' => $termo,
                'lang' => 'pt_BR'
            ];
            
            if ($modelo) {
                $params['model'] = $modelo;
            }
            if ($ano) {
                $params['year'] = $ano;
            }

            $url = $this->baseUrl . 'index.html?' . http_build_query($params);
            
            // Fazer requisição HTTP
            $ch = curl_init();
            curl_setopt_array($ch, [
                CURLOPT_URL => $url,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_FOLLOWLOCATION => true,
                CURLOPT_TIMEOUT => $this->timeout,
                CURLOPT_USERAGENT => $this->userAgent,
                CURLOPT_HTTPHEADER => [
                    'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
                    'Accept-Language: pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7',
                    'Accept-Encoding: gzip, deflate, br',
                    'Connection: keep-alive',
                    'Upgrade-Insecure-Requests: 1'
                ],
                CURLOPT_ENCODING => 'gzip, deflate, br'
            ]);

            $html = 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 !== 200) {
                throw new Exception("HTTP $httpCode retornado");
            }

            // Parsear HTML
            $pecas = $this->parsearResultados($html);
            
            // Verificar se estrutura mudou (nenhum resultado pode indicar mudança no site)
            if (empty($pecas) && strlen($html) > 1000) {
                // Pode ter mudado a estrutura do site
                $notif = new \Modules\GestorY\Services\NotificationService();
                $notif->notificarMudancaSite("Nenhum resultado encontrado, mas HTML retornado. Possível mudança na estrutura do site.");
            }

            // Salvar no cache (1 hora)
            $this->setCache($cacheKey, $pecas, 3600);

            $this->log('pesquisa', 'Pesquisa realizada', [
                'termo' => $termo,
                'modelo' => $modelo,
                'ano' => $ano,
                'resultados' => count($pecas)
            ], true);

            return $pecas;
        } catch (Exception $e) {
            $this->log('erro', 'Erro na pesquisa', [
                'termo' => $termo,
                'erro' => $e->getMessage()
            ], false);
            
            // Notificar sobre erro
            $notif = new \Modules\GestorY\Services\NotificationService();
            $notif->notificarErroScraping($e->getMessage(), [
                'termo' => $termo,
                'modelo' => $modelo,
                'ano' => $ano
            ]);
            
            throw $e;
        }
    }

    /**
     * Obtém detalhes de uma peça específica
     */
    public function getPecaDetalhes(string $codigo): ?array {
        try {
            // Verificar cache
            $cacheKey = md5("peca_{$codigo}");
            $cached = $this->getCache($cacheKey);
            if ($cached !== null) {
                return $cached;
            }

            // Buscar peça no banco primeiro
            $stmt = $this->pdo->prepare('SELECT * FROM gestory_pecas WHERE codigo_yamaha = ? AND tenant_id = ? LIMIT 1');
            $stmt->execute([$codigo, $this->tenantId]);
            $peca = $stmt->fetch();

            if ($peca) {
                // Converter JSON fields
                if (!empty($peca['modelo_compativel'])) {
                    $peca['modelo_compativel'] = json_decode($peca['modelo_compativel'], true) ?: [];
                }
                return $peca;
            }

            // Se não encontrou, tentar buscar do site
            // Nota: A API do YPEC pode requerer autenticação ou ter estrutura diferente
            // Por enquanto, retornamos null e sugerimos importação manual
            
            return null;
        } catch (Exception $e) {
            $this->log('erro', 'Erro ao buscar detalhes', [
                'codigo' => $codigo,
                'erro' => $e->getMessage()
            ], false);
            return null;
        }
    }

    /**
     * Parseia HTML e extrai informações das peças
     */
    private function parsearResultados(string $html): array {
        $pecas = [];
        
        // Criar DOMDocument
        libxml_use_internal_errors(true);
        $dom = new \DOMDocument();
        @$dom->loadHTML('<?xml encoding="UTF-8">' . $html);
        libxml_clear_errors();
        
        $xpath = new \DOMXPath($dom);
        
        // Tentar encontrar elementos de peças (ajustar selectors conforme estrutura real do site)
        // Nota: O site Yamaha pode usar JavaScript para carregar dados, então pode ser necessário usar Selenium/Puppeteer
        $items = $xpath->query('//div[contains(@class, "part-item")] | //tr[contains(@class, "part-row")]');
        
        foreach ($items as $item) {
            try {
                $codigo = $this->extractText($xpath, $item, './/span[contains(@class, "part-code")] | .//td[1]');
                $nome = $this->extractText($xpath, $item, './/span[contains(@class, "part-name")] | .//td[2]');
                $preco = $this->extractText($xpath, $item, './/span[contains(@class, "price")] | .//td[3]');
                $imagem = $this->extractAttribute($xpath, $item, './/img', 'src');
                
                if ($codigo && $nome) {
                    $pecas[] = [
                        'codigo_yamaha' => trim($codigo),
                        'nome' => trim($nome),
                        'preco_yamaha' => $this->parsePrice($preco),
                        'imagem_url' => $imagem ? $this->normalizeUrl($imagem) : null,
                        'status' => 'disponivel'
                    ];
                }
            } catch (Exception $e) {
                // Continuar processando outras peças
                continue;
            }
        }
        
        // Se não encontrou resultados com selectors padrão, tentar extrair de JSON embutido
        if (empty($pecas)) {
            $pecas = $this->extractFromJson($html);
        }
        
        return $pecas;
    }

    /**
     * Tenta extrair dados de JSON embutido no HTML
     */
    private function extractFromJson(string $html): array {
        $pecas = [];
        
        // Procurar por scripts com dados JSON
        if (preg_match('/var\s+partsData\s*=\s*(\[.*?\]);/s', $html, $matches)) {
            $json = json_decode($matches[1], true);
            if (is_array($json)) {
                foreach ($json as $item) {
                    if (isset($item['code']) && isset($item['name'])) {
                        $pecas[] = [
                            'codigo_yamaha' => $item['code'],
                            'nome' => $item['name'],
                            'preco_yamaha' => isset($item['price']) ? $this->parsePrice($item['price']) : null,
                            'imagem_url' => $item['image'] ?? null,
                            'status' => $item['status'] ?? 'disponivel'
                        ];
                    }
                }
            }
        }
        
        return $pecas;
    }

    /**
     * Extrai texto de um elemento
     */
    private function extractText(\DOMXPath $xpath, \DOMNode $context, string $query): ?string {
        $nodes = $xpath->query($query, $context);
        if ($nodes->length > 0) {
            return trim($nodes->item(0)->textContent);
        }
        return null;
    }

    /**
     * Extrai atributo de um elemento
     */
    private function extractAttribute(\DOMXPath $xpath, \DOMNode $context, string $query, string $attr): ?string {
        $nodes = $xpath->query($query, $context);
        if ($nodes->length > 0) {
            return $nodes->item(0)->getAttribute($attr);
        }
        return null;
    }

    /**
     * Parseia preço de string para decimal
     */
    private function parsePrice(?string $priceStr): ?float {
        if (!$priceStr) return null;
        $priceStr = preg_replace('/[^\d,.]/', '', $priceStr);
        $priceStr = str_replace(',', '.', $priceStr);
        return is_numeric($priceStr) ? (float)$priceStr : null;
    }

    /**
     * Normaliza URL
     */
    private function normalizeUrl(string $url): string {
        if (strpos($url, 'http') === 0) {
            return $url;
        }
        if (strpos($url, '//') === 0) {
            return 'https:' . $url;
        }
        return $this->baseUrl . ltrim($url, '/');
    }

    /**
     * Salva peça no banco de dados
     */
    public function salvarPeca(array $dados): int {
        // Verificar se já existe
        $stmt = $this->pdo->prepare('SELECT id FROM gestory_pecas WHERE tenant_id = ? AND codigo_yamaha = ? LIMIT 1');
        $stmt->execute([$this->tenantId, $dados['codigo_yamaha']]);
        $existing = $stmt->fetch();
        
        $modeloJson = !empty($dados['modelo_compativel']) 
            ? json_encode($dados['modelo_compativel']) 
            : null;
        
        if ($existing) {
            // Atualizar
            $stmt = $this->pdo->prepare('UPDATE gestory_pecas SET
                nome = ?,
                descricao = ?,
                categoria = ?,
                modelo_compativel = ?,
                ano_compativel = ?,
                preco_yamaha = ?,
                imagem_url = ?,
                diagrama_url = ?,
                status = ?,
                ultima_atualizacao = NOW()
                WHERE id = ? AND tenant_id = ?');
            
            $stmt->execute([
                $dados['nome'],
                $dados['descricao'] ?? null,
                $dados['categoria'] ?? null,
                $modeloJson,
                $dados['ano_compativel'] ?? null,
                $dados['preco_yamaha'] ?? null,
                $dados['imagem_url'] ?? null,
                $dados['diagrama_url'] ?? null,
                $dados['status'] ?? 'disponivel',
                $existing['id'],
                $this->tenantId
            ]);
            
            return (int)$existing['id'];
        } else {
            // Inserir
            $stmt = $this->pdo->prepare('INSERT INTO gestory_pecas 
                (tenant_id, codigo_yamaha, nome, descricao, categoria, modelo_compativel, ano_compativel, 
                 preco_yamaha, imagem_url, diagrama_url, status, ultima_atualizacao)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW())');
            
            $stmt->execute([
                $this->tenantId,
                $dados['codigo_yamaha'],
                $dados['nome'],
                $dados['descricao'] ?? null,
                $dados['categoria'] ?? null,
                $modeloJson,
                $dados['ano_compativel'] ?? null,
                $dados['preco_yamaha'] ?? null,
                $dados['imagem_url'] ?? null,
                $dados['diagrama_url'] ?? null,
                $dados['status'] ?? 'disponivel'
            ]);
            
            return (int)$this->pdo->lastInsertId();
        }
    }

    /**
     * Cache
     */
    private function getCache(string $key): ?array {
        $stmt = $this->pdo->prepare('SELECT dados_json FROM gestory_cache 
            WHERE tenant_id = ? AND chave_cache = ? AND expires_at > NOW() LIMIT 1');
        $stmt->execute([$this->tenantId, $key]);
        $row = $stmt->fetch();
        
        if ($row) {
            return json_decode($row['dados_json'], true);
        }
        
        return null;
    }

    private function setCache(string $key, array $data, int $ttl): void {
        $expires = date('Y-m-d H:i:s', time() + $ttl);
        $stmt = $this->pdo->prepare('INSERT INTO gestory_cache 
            (tenant_id, chave_cache, dados_json, expires_at)
            VALUES (?, ?, ?, ?)
            ON DUPLICATE KEY UPDATE
                dados_json = VALUES(dados_json),
                expires_at = VALUES(expires_at)');
        
        $stmt->execute([$this->tenantId, $key, json_encode($data), $expires]);
    }

    /**
     * Log
     */
    private function log(string $tipo, string $acao, array $dados = [], bool $sucesso = true): void {
        try {
            $stmt = $this->pdo->prepare('INSERT INTO gestory_logs 
                (tenant_id, tipo, acao, codigo_peca, mensagem, dados_json, sucesso)
                VALUES (?, ?, ?, ?, ?, ?, ?)');
            
            $stmt->execute([
                $this->tenantId,
                $tipo,
                $acao,
                $dados['codigo_yamaha'] ?? $dados['codigo'] ?? null,
                $dados['mensagem'] ?? $acao,
                json_encode($dados),
                $sucesso ? 1 : 0
            ]);
        } catch (Exception $e) {
            error_log("[GestorY] Erro ao salvar log: " . $e->getMessage());
        }
    }
}

