#!/usr/bin/env python3
"""
ABR Telecom Validation API v2.0
Valida números de telefone brasileiros via portal ABR Telecom
Com resolução automática de CAPTCHA via 2Captcha

Porta: 9003
"""

from flask import Flask, jsonify, request
from flask_cors import CORS
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import undetected_chromedriver as uc
import requests
import time
import re
import os
from datetime import datetime

app = Flask(__name__)
CORS(app)

# ============= CONFIGURAÇÃO =============

# 2Captcha API Key (obter em https://2captcha.com)
TWOCAPTCHA_API_KEY = os.getenv('TWOCAPTCHA_API_KEY', '')

# URL base ABR Telecom
ABR_URL = "https://consultanumero.abrtelecom.com.br/consultanumero/consulta/consultaSituacaoAtualCtg"

# Site Key do reCAPTCHA (será extraído dinamicamente)
RECAPTCHA_SITE_KEY = None

# Cache de resultados
cache = {'results': {}}

# ============= LOGGING =============

def log(message, level="INFO"):
    """Log com timestamp"""
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    print(f"[{timestamp}] [{level}] {message}")


# ============= 2CAPTCHA SOLVER =============

class TwoCaptchaSolver:
    """Resolve reCAPTCHA usando 2Captcha API"""

    def __init__(self, api_key):
        self.api_key = api_key
        self.base_url = "http://2captcha.com"

    def get_balance(self):
        """Retorna saldo da conta"""
        try:
            url = f"{self.base_url}/res.php?key={self.api_key}&action=getbalance"
            response = requests.get(url, timeout=10)
            return float(response.text)
        except:
            return None

    def solve_recaptcha(self, site_key, page_url):
        """Resolve reCAPTCHA v2 e retorna token"""
        log("[2Captcha] Enviando CAPTCHA para resolução...")

        # 1. Envia CAPTCHA
        submit_url = f"{self.base_url}/in.php"
        params = {
            'key': self.api_key,
            'method': 'userrecaptcha',
            'googlekey': site_key,
            'pageurl': page_url,
            'json': 1
        }

        response = requests.get(submit_url, params=params, timeout=30)
        data = response.json()

        if data.get('status') != 1:
            raise Exception(f"Erro ao enviar CAPTCHA: {data.get('request')}")

        captcha_id = data['request']
        log(f"[2Captcha] CAPTCHA ID: {captcha_id}")

        # 2. Aguarda resolução (polling)
        result_url = f"{self.base_url}/res.php"
        params = {
            'key': self.api_key,
            'action': 'get',
            'id': captcha_id,
            'json': 1
        }

        max_attempts = 30  # 30 * 5s = 150s máximo
        for attempt in range(max_attempts):
            time.sleep(5)
            response = requests.get(result_url, params=params, timeout=30)
            data = response.json()

            if data.get('status') == 1:
                token = data['request']
                log(f"[2Captcha] CAPTCHA resolvido! Token: {token[:50]}...")
                return token

            if data.get('request') != 'CAPCHA_NOT_READY':
                raise Exception(f"Erro: {data.get('request')}")

            log(f"[2Captcha] Aguardando... ({attempt + 1}/{max_attempts})")

        raise Exception("Timeout: CAPTCHA não resolvido em 150s")


# ============= ABR TELECOM SCRAPER =============

class ABRTelecomScraper:
    def __init__(self):
        self.driver = None
        self.session_ready = False
        self.captcha_solver = TwoCaptchaSolver(TWOCAPTCHA_API_KEY) if TWOCAPTCHA_API_KEY else None
        self.recaptcha_site_key = None

    def init_driver(self, headless=True):
        """Inicializa Chrome com undetected-chromedriver"""
        log(f"Inicializando driver (headless={headless})...")

        try:
            options = uc.ChromeOptions()
            options.add_argument('--no-sandbox')
            options.add_argument('--disable-dev-shm-usage')
            options.add_argument('--disable-gpu')
            options.add_argument('--window-size=1920,1080')

            # Anti-detection settings
            options.add_argument('--disable-blink-features=AutomationControlled')
            options.add_argument('--disable-extensions')
            options.add_argument('--disable-infobars')
            options.add_argument('--lang=pt-BR')
            options.add_argument('--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36')

            if headless:
                options.add_argument('--headless=new')

            self.driver = uc.Chrome(options=options, use_subprocess=True)
            self.driver.get(ABR_URL)
            time.sleep(3)

            # Extrai site key do reCAPTCHA
            self._extract_recaptcha_key()

            log("Driver inicializado com sucesso")
            return True

        except Exception as e:
            log(f"Erro ao inicializar driver: {e}", "ERROR")
            return False

    def _extract_recaptcha_key(self):
        """Extrai a site key do reCAPTCHA da página"""
        try:
            # Procura pelo elemento do reCAPTCHA
            recaptcha_div = self.driver.find_element(By.CLASS_NAME, "g-recaptcha")
            self.recaptcha_site_key = recaptcha_div.get_attribute("data-sitekey")
            log(f"reCAPTCHA site key: {self.recaptcha_site_key}")
        except:
            # Tenta extrair do JavaScript
            try:
                page_source = self.driver.page_source
                match = re.search(r'sitekey["\']?\s*[:=]\s*["\']([^"\']+)["\']', page_source)
                if match:
                    self.recaptcha_site_key = match.group(1)
                    log(f"reCAPTCHA site key (via regex): {self.recaptcha_site_key}")
            except:
                log("Não foi possível extrair reCAPTCHA site key", "WARN")

    def solve_captcha_auto(self):
        """Resolve CAPTCHA automaticamente usando 2Captcha"""
        if not self.captcha_solver:
            log("2Captcha não configurado", "WARN")
            return False

        if not self.recaptcha_site_key:
            log("Site key do reCAPTCHA não disponível", "ERROR")
            return False

        try:
            # Obtém token do 2Captcha
            token = self.captcha_solver.solve_recaptcha(
                self.recaptcha_site_key,
                ABR_URL
            )

            # Injeta token na página
            self.driver.execute_script(f'''
                var textarea = document.getElementById("g-recaptcha-response");
                if (!textarea) {{
                    textarea = document.createElement("textarea");
                    textarea.id = "g-recaptcha-response";
                    textarea.name = "g-recaptcha-response";
                    document.body.appendChild(textarea);
                }}
                textarea.innerHTML = "{token}";
                textarea.style.display = "block";
            ''')

            # Tenta disparar callback do reCAPTCHA
            self.driver.execute_script('''
                if (typeof ___grecaptcha_cfg !== 'undefined') {
                    var clients = ___grecaptcha_cfg.clients;
                    for (var key in clients) {
                        if (clients[key] && clients[key].T && clients[key].T.T) {
                            var callback = clients[key].T.T.callback;
                            if (typeof callback === 'function') {
                                callback(arguments[0]);
                            }
                        }
                    }
                }
            ''', token)

            time.sleep(2)
            self.session_ready = True
            log("CAPTCHA resolvido com sucesso!")
            return True

        except Exception as e:
            log(f"Erro ao resolver CAPTCHA: {e}", "ERROR")
            return False

    def consultar_numero(self, telefone):
        """Consulta situação atual de um número"""
        if not self.driver:
            return {'success': False, 'error': 'Driver não inicializado'}

        # Auto-resolve CAPTCHA se necessário e configurado
        if not self.session_ready and self.captcha_solver:
            if not self.solve_captcha_auto():
                return {'success': False, 'error': 'Falha ao resolver CAPTCHA'}

        try:
            numero_limpo = re.sub(r'\D', '', telefone)

            if len(numero_limpo) < 10 or len(numero_limpo) > 11:
                return {
                    'success': False,
                    'error': 'Número deve ter 10 ou 11 dígitos',
                    'telefone': telefone
                }

            # Navega para a página se necessário
            current_url = self.driver.current_url
            if 'consultanumero' not in current_url:
                self.driver.get(ABR_URL)
                time.sleep(2)

            # Preenche campo de telefone
            input_telefone = WebDriverWait(self.driver, 10).until(
                EC.presence_of_element_located((By.ID, "telefone"))
            )
            input_telefone.clear()
            input_telefone.send_keys(numero_limpo)

            # Clica no botão de consulta
            btn_consultar = WebDriverWait(self.driver, 10).until(
                EC.element_to_be_clickable((By.ID, "btnConsultar"))
            )
            btn_consultar.click()

            time.sleep(3)

            # Extrai resultado
            resultado = self.extrair_resultado()

            log(f"Consulta: {numero_limpo} -> {resultado.get('status', 'erro')}")

            return {
                'success': True,
                'telefone': telefone,
                'telefone_formatado': self.formatar_telefone(numero_limpo),
                'data': resultado
            }

        except Exception as e:
            error_msg = str(e)
            log(f"Erro na consulta: {error_msg}", "ERROR")

            # Se erro relacionado a CAPTCHA, marca sessão como inválida
            if 'captcha' in error_msg.lower() or 'recaptcha' in error_msg.lower():
                self.session_ready = False

            return {'success': False, 'error': error_msg, 'telefone': telefone}

    def extrair_resultado(self):
        """Extrai dados da tabela de resultados"""
        try:
            # Aguarda tabela de resultados
            tabela = WebDriverWait(self.driver, 10).until(
                EC.presence_of_element_located((By.CSS_SELECTOR, "table.table"))
            )

            linhas = tabela.find_elements(By.TAG_NAME, "tr")

            if len(linhas) > 1:
                celulas = linhas[1].find_elements(By.TAG_NAME, "td")
                if len(celulas) >= 3:
                    return {
                        'data': celulas[0].text.strip(),
                        'operadora': celulas[1].text.strip(),
                        'razao_social': celulas[2].text.strip(),
                        'status': 'ativo'
                    }

            # Verifica mensagem de não encontrado
            try:
                alert = self.driver.find_element(By.CSS_SELECTOR, ".alert-warning, .alert-info")
                if alert:
                    return {'status': 'nao_encontrado', 'mensagem': alert.text}
            except:
                pass

            return {'status': 'nao_encontrado'}

        except Exception as e:
            return {'status': 'erro', 'erro': str(e)}

    def formatar_telefone(self, numero):
        """Formata número para exibição"""
        if len(numero) == 11:
            return f"({numero[:2]}) {numero[2:7]}-{numero[7:]}"
        elif len(numero) == 10:
            return f"({numero[:2]}) {numero[2:6]}-{numero[6:]}"
        return numero

    def close(self):
        """Fecha o driver"""
        if self.driver:
            try:
                self.driver.quit()
                log("Driver fechado")
            except:
                pass
            self.driver = None
            self.session_ready = False


# Instância global
scraper = ABRTelecomScraper()


# ============= ENDPOINTS =============

@app.route('/')
def index():
    """Informações da API"""
    return jsonify({
        'service': 'ABR Telecom Validation API',
        'version': '2.0.0',
        'port': 9003,
        'captcha': '2Captcha (automático)' if TWOCAPTCHA_API_KEY else 'Manual',
        'session_ready': scraper.session_ready,
        'endpoints': {
            '/api/init': 'POST - Inicializa sessão',
            '/api/status': 'GET - Status da sessão',
            '/api/validate': 'POST - Valida número único',
            '/api/validate/batch': 'POST - Valida múltiplos números',
            '/api/balance': 'GET - Saldo 2Captcha',
            '/api/close': 'POST - Fecha sessão',
            '/health': 'GET - Health check'
        }
    })


@app.route('/health')
def health():
    """Health check"""
    return jsonify({
        'status': 'ok',
        'session_ready': scraper.session_ready,
        'driver_active': scraper.driver is not None,
        'captcha_service': '2captcha' if TWOCAPTCHA_API_KEY else 'manual',
        'cache_size': len(cache['results'])
    })


@app.route('/api/balance', methods=['GET'])
def get_balance():
    """Retorna saldo do 2Captcha"""
    if not TWOCAPTCHA_API_KEY:
        return jsonify({'success': False, 'error': '2Captcha não configurado'})

    try:
        solver = TwoCaptchaSolver(TWOCAPTCHA_API_KEY)
        balance = solver.get_balance()
        if balance is not None:
            return jsonify({'success': True, 'balance_usd': balance})
        return jsonify({'success': False, 'error': 'Erro ao consultar saldo'})
    except Exception as e:
        return jsonify({'success': False, 'error': str(e)})


@app.route('/api/init', methods=['POST'])
def init_session():
    """Inicializa sessão do navegador"""
    try:
        data = request.get_json() or {}
        headless = data.get('headless', True)
        auto_captcha = data.get('auto_captcha', True)

        # Fecha sessão anterior se existir
        if scraper.driver:
            scraper.close()

        success = scraper.init_driver(headless=headless)

        if not success:
            return jsonify({'success': False, 'error': 'Falha ao inicializar driver'}), 500

        # Resolve CAPTCHA automaticamente se configurado
        captcha_ok = False
        if auto_captcha and TWOCAPTCHA_API_KEY:
            captcha_ok = scraper.solve_captcha_auto()

        return jsonify({
            'success': True,
            'session_ready': scraper.session_ready,
            'captcha_solved': captcha_ok,
            'message': 'Sessão iniciada' + (' com CAPTCHA resolvido' if captcha_ok else ' - resolva o CAPTCHA manualmente')
        })

    except Exception as e:
        log(f"Erro ao inicializar: {e}", "ERROR")
        return jsonify({'success': False, 'error': str(e)}), 500


@app.route('/api/captcha-solved', methods=['POST'])
def captcha_solved():
    """Marca CAPTCHA como resolvido (modo manual)"""
    scraper.session_ready = True
    return jsonify({
        'success': True,
        'message': 'Sessão marcada como pronta'
    })


@app.route('/api/status', methods=['GET'])
def session_status():
    """Retorna status da sessão"""
    return jsonify({
        'session_ready': scraper.session_ready,
        'driver_active': scraper.driver is not None,
        'cache_size': len(cache['results']),
        'recaptcha_key': scraper.recaptcha_site_key
    })


@app.route('/api/close', methods=['POST'])
def close_session():
    """Fecha a sessão do navegador"""
    scraper.close()
    return jsonify({'success': True, 'message': 'Sessão fechada'})


@app.route('/api/validate', methods=['POST'])
def validate_single():
    """Valida um número único"""
    data = request.get_json()

    if not data or 'telefone' not in data:
        return jsonify({'error': 'Campo telefone é obrigatório'}), 400

    telefone = data['telefone']
    cache_key = re.sub(r'\D', '', telefone)

    # Verifica cache
    if cache_key in cache['results']:
        cached = cache['results'][cache_key].copy()
        cached['cached'] = True
        log(f"Cache hit: {cache_key}")
        return jsonify(cached)

    # Inicializa driver se necessário
    if not scraper.driver:
        log("Auto-inicializando driver...")
        scraper.init_driver(headless=True)

    resultado = scraper.consultar_numero(telefone)

    # Salva no cache se sucesso
    if resultado.get('success'):
        cache['results'][cache_key] = resultado

    return jsonify(resultado)


@app.route('/api/validate/batch', methods=['POST'])
def validate_batch():
    """Valida múltiplos números"""
    data = request.get_json()

    if not data or 'telefones' not in data:
        return jsonify({'error': 'Campo telefones é obrigatório'}), 400

    if not isinstance(data['telefones'], list):
        return jsonify({'error': 'telefones deve ser uma lista'}), 400

    if len(data['telefones']) > 100:
        return jsonify({'error': 'Máximo 100 números por requisição'}), 400

    # Inicializa driver se necessário
    if not scraper.driver:
        log("Auto-inicializando driver para batch...")
        scraper.init_driver(headless=True)

    resultados = []
    total = len(data['telefones'])

    for i, telefone in enumerate(data['telefones']):
        cache_key = re.sub(r'\D', '', telefone)

        # Verifica cache primeiro
        if cache_key in cache['results']:
            cached = cache['results'][cache_key].copy()
            cached['cached'] = True
            resultados.append(cached)
            log(f"[Batch] {i+1}/{total} - {telefone} (cache)")
        else:
            resultado = scraper.consultar_numero(telefone)
            resultados.append(resultado)

            if resultado.get('success'):
                cache['results'][cache_key] = resultado

            log(f"[Batch] {i+1}/{total} - {telefone}")
            time.sleep(1)  # Rate limiting

    return jsonify({
        'success': True,
        'total': len(resultados),
        'validos': sum(1 for r in resultados if r.get('success')),
        'cached': sum(1 for r in resultados if r.get('cached')),
        'resultados': resultados
    })


@app.route('/api/cache/clear', methods=['POST'])
def clear_cache():
    """Limpa o cache de resultados"""
    count = len(cache['results'])
    cache['results'] = {}
    return jsonify({'success': True, 'cleared': count})


# ============= MAIN =============

if __name__ == '__main__':
    print("=" * 60)
    print("  ABR Telecom Validation API v2.0")
    print("=" * 60)
    print(f"  Porta: 9003")
    print(f"  CAPTCHA: {'2Captcha (automático)' if TWOCAPTCHA_API_KEY else 'Manual'}")
    if TWOCAPTCHA_API_KEY:
        print(f"  API Key: {TWOCAPTCHA_API_KEY[:10]}...")
    else:
        print("  API Key: NÃO CONFIGURADA")
        print("  Configure: export TWOCAPTCHA_API_KEY='sua_key'")
    print()
    print("  Endpoints:")
    print("    POST /api/init           - Inicia sessão")
    print("    POST /api/validate       - Valida número único")
    print("    POST /api/validate/batch - Valida lote (até 100)")
    print("    GET  /api/balance        - Saldo 2Captcha")
    print("    GET  /api/status         - Status da sessão")
    print()
    print("  Acesso via Tailscale:")
    print("    http://100.75.88.8:9003/")
    print("=" * 60)

    app.run(host='0.0.0.0', port=9003, debug=False, threaded=True)
