#!/usr/bin/env python3
"""Backend da ferramenta VSL - Flask porta 5053"""
import json
import os
import re
import io
import requests
from flask import Flask, request, Response, jsonify
from flask_cors import CORS
import anthropic

try:
    from bs4 import BeautifulSoup
    BS4_OK = True
except ImportError:
    BS4_OK = False

try:
    import pypdf
    PYPDF_OK = True
except ImportError:
    PYPDF_OK = False

try:
    from docx import Document as DocxDocument
    DOCX_OK = True
except ImportError:
    DOCX_OK = False

app = Flask(__name__)
CORS(app, origins='*', supports_credentials=True)

ANTHROPIC_API_KEY = "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"
SUPABASE_URL = "https://qrweeonylthrcbbalkwn.supabase.co"
SUPABASE_SERVICE_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InFyd2Vlb255bHRocmNiYmFsa3duIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImlhdCI6MTc3NDE3ODY4NywiZXhwIjoyMDg5NzU0Njg3fQ.RPh6CBasd2_JLQi5B5mwYCwIySFim-jJThSGipaYCd4"

client = anthropic.Anthropic(api_key=ANTHROPIC_API_KEY)

SYSTEM_ENTREVISTA = """Você é um especialista em criação de VSL (Video Sales Letter) com 15 anos de experiência em copywriting de resposta direta. Seu objetivo é coletar as informações necessárias para criar um roteiro de VSL de alta conversão.

IMPORTANTE — SOBRE LINKS E ARQUIVOS:
Quando o usuário enviar uma URL ou arquivo, o sistema já faz a extração do conteúdo automaticamente e injeta no final da mensagem entre marcadores [Conteúdo extraído de ...] ou [Conteúdo do arquivo enviado]. USE essas informações como se o usuário tivesse te contado diretamente. NÃO diga que não consegue acessar links — o conteúdo já está disponível na mensagem. Confirme o que foi extraído e use para avançar a entrevista.

Faça UMA pergunta por vez, de forma conversacional e amigável. Após coletar TODAS as informações necessárias, diga exatamente: "GERAR_VSL" para acionar a geração do roteiro.

Informações que você precisa coletar (nessa ordem):
1. Nome do produto/serviço
2. Público-alvo (quem é, idade, situação)
3. Principal dor ou problema que resolve
4. Resultado/transformação que o cliente terá
5. O mecanismo único (como funciona, o que diferencia)
6. Prova social (depoimentos, números, casos de sucesso)
7. Preço e condições de pagamento
8. Garantia oferecida
9. Bônus incluídos (se houver)
10. Prazo ou urgência (se houver)

Se o conteúdo extraído de links ou arquivos já responder várias perguntas de uma vez, consolide as informações e confirme com o usuário antes de avançar. Isso acelera o processo.

Comece se apresentando brevemente e fazendo a primeira pergunta sobre o nome do produto."""

SYSTEM_GERACAO = """Você é um copywriter especialista em VSL (Video Sales Letter) de alta conversão. Com base nas informações coletadas na conversa, crie um roteiro completo e profissional.

ESTRUTURA OBRIGATÓRIA DO ROTEIRO VSL:
1. GANCHO (0-30s): frase de abertura poderosa que para o scroll
2. PROBLEMA (30s-2min): amplificação da dor, o cliente se vê nessa situação
3. AGITAÇÃO (2-4min): consequências de não resolver o problema
4. HISTÓRIA (4-7min): história de origem ou caso de sucesso (relatable)
5. SOLUÇÃO (7-10min): apresentação do produto como a solução
6. MECANISMO (10-13min): como funciona, o que diferencia
7. PROVA SOCIAL (13-16min): depoimentos, números, resultados
8. OFERTA (16-18min): o que recebe, preço, condições
9. GARANTIA (18-19min): elimina o risco
10. URGÊNCIA/ESCASSEZ (19-20min): por que agir agora
11. CTA FINAL (20min): chamada para ação clara e direta

Formate bem o roteiro com títulos de seção, indicações de tom de voz, pausas dramáticas e marcações [VISUAL: ...] para sugestões de imagem/câmera. Escreva em português do Brasil, tom persuasivo mas autêntico.

Use as informações que o usuário forneceu durante a entrevista para personalizar cada seção."""


def supa_headers(token=None):
    """Headers para Supabase REST API."""
    key = token if token else SUPABASE_SERVICE_KEY
    return {
        "apikey": SUPABASE_SERVICE_KEY,
        "Authorization": f"Bearer {key}",
        "Content-Type": "application/json",
        "Prefer": "return=representation"
    }


def supa_get(path, token=None, params=None):
    resp = requests.get(f"{SUPABASE_URL}/rest/v1/{path}", headers=supa_headers(token), params=params)
    return resp


def supa_post(path, data, token=None):
    resp = requests.post(f"{SUPABASE_URL}/rest/v1/{path}", headers=supa_headers(token), json=data)
    return resp


def supa_patch(path, data, token=None):
    resp = requests.patch(f"{SUPABASE_URL}/rest/v1/{path}", headers=supa_headers(token), json=data)
    return resp


def supa_delete(path, token=None):
    resp = requests.delete(f"{SUPABASE_URL}/rest/v1/{path}", headers=supa_headers(token))
    return resp


def get_mensagens(sessao_id):
    """Busca mensagens de uma sessão ordenadas por criacao."""
    resp = supa_get(
        f"mensagens_vsl?sessao_id=eq.{sessao_id}&order=criado_em.asc",
        token=SUPABASE_SERVICE_KEY
    )
    if resp.status_code == 200:
        return resp.json()
    return []


def salvar_mensagem(sessao_id, role, content):
    """Salva mensagem no banco."""
    resp = supa_post("mensagens_vsl", {
        "sessao_id": sessao_id,
        "role": role,
        "content": content
    }, token=SUPABASE_SERVICE_KEY)
    return resp.status_code in (200, 201)


def deve_gerar_vsl(mensagens):
    """Verifica se alguma mensagem do assistente contém GERAR_VSL."""
    for msg in mensagens:
        if msg.get("role") == "assistant" and "GERAR_VSL" in msg.get("content", ""):
            return True
    return False


def atualizar_titulo_sessao(sessao_id, titulo):
    """Atualiza o título da sessão."""
    supa_patch(
        f"sessoes_vsl?id=eq.{sessao_id}",
        {"titulo": titulo, "atualizado_em": "now()"},
        token=SUPABASE_SERVICE_KEY
    )


def atualizar_status_sessao(sessao_id, status):
    """Atualiza status da sessão."""
    supa_patch(
        f"sessoes_vsl?id=eq.{sessao_id}",
        {"status": status, "atualizado_em": "now()"},
        token=SUPABASE_SERVICE_KEY
    )


def extrair_texto_url(url: str) -> str:
    """Faz scraping de uma URL e retorna o texto principal."""
    try:
        headers = {"User-Agent": "Mozilla/5.0 (compatible; VSL-Bot/1.0)"}
        r = requests.get(url, headers=headers, timeout=15)
        r.raise_for_status()
        if not BS4_OK:
            return r.text[:3000]
        soup = BeautifulSoup(r.text, "lxml")
        # Remove scripts, estilos e nav
        for tag in soup(["script", "style", "nav", "header", "footer", "aside"]):
            tag.decompose()
        texto = soup.get_text(separator="\n", strip=True)
        # Limpa linhas vazias excessivas
        linhas = [l for l in texto.splitlines() if l.strip()]
        return "\n".join(linhas)[:5000]
    except Exception as e:
        return f"[Erro ao acessar URL: {e}]"


def extrair_texto_arquivo(file_bytes: bytes, filename: str, mimetype: str) -> str:
    """Extrai texto de PDF, DOCX ou TXT."""
    ext = filename.rsplit(".", 1)[-1].lower() if "." in filename else ""

    if ext == "pdf" or "pdf" in mimetype:
        if PYPDF_OK:
            try:
                reader = pypdf.PdfReader(io.BytesIO(file_bytes))
                texto = "\n".join(p.extract_text() or "" for p in reader.pages)
                return texto[:8000]
            except Exception as e:
                return f"[Erro ao ler PDF: {e}]"
        return "[pypdf não instalado - instale com: pip install pypdf]"

    if ext in ("docx", "doc") or "word" in mimetype:
        if DOCX_OK:
            try:
                doc = DocxDocument(io.BytesIO(file_bytes))
                texto = "\n".join(p.text for p in doc.paragraphs if p.text.strip())
                return texto[:8000]
            except Exception as e:
                return f"[Erro ao ler DOCX: {e}]"
        return "[python-docx não instalado]"

    # TXT / outros textos
    try:
        return file_bytes.decode("utf-8", errors="ignore")[:8000]
    except Exception:
        return "[Arquivo não pôde ser lido como texto]"


def detectar_urls(texto: str) -> list:
    """Extrai URLs de um texto."""
    return re.findall(r'https?://[^\s<>"\']+', texto)


@app.route("/api/health", methods=["GET"])
def health():
    return jsonify({"status": "ok", "service": "vsl-backend"})


@app.route("/api/upload", methods=["POST"])
def upload_arquivo():
    """Recebe arquivo, extrai texto e retorna para o frontend incluir no contexto."""
    if "file" not in request.files:
        return jsonify({"error": "Nenhum arquivo enviado"}), 400
    f = request.files["file"]
    if not f.filename:
        return jsonify({"error": "Nome de arquivo inválido"}), 400

    file_bytes = f.read()
    if len(file_bytes) > 20 * 1024 * 1024:  # 20MB máx
        return jsonify({"error": "Arquivo muito grande (máx 20MB)"}), 400

    texto = extrair_texto_arquivo(file_bytes, f.filename, f.content_type or "")
    return jsonify({
        "nome": f.filename,
        "tamanho": len(file_bytes),
        "texto": texto,
        "chars": len(texto)
    })


@app.route("/api/fetch-url", methods=["POST"])
def fetch_url():
    """Faz scraping de uma URL e retorna o conteúdo."""
    data = request.get_json(force=True) or {}
    url = (data.get("url") or "").strip()
    if not url.startswith("http"):
        return jsonify({"error": "URL inválida"}), 400
    texto = extrair_texto_url(url)
    return jsonify({"url": url, "texto": texto, "chars": len(texto)})


@app.route("/api/sessao", methods=["POST"])
def criar_sessao():
    """Cria nova sessão VSL e retorna a primeira mensagem do assistente."""
    data = request.get_json()
    usuario_id = data.get("usuario_id")
    token = data.get("token", SUPABASE_SERVICE_KEY)

    if not usuario_id:
        return jsonify({"error": "usuario_id obrigatório"}), 400

    # Cria sessão no Supabase
    resp = supa_post("sessoes_vsl", {
        "usuario_id": usuario_id,
        "titulo": "Nova VSL",
        "status": "entrevista"
    }, token=SUPABASE_SERVICE_KEY)

    if resp.status_code not in (200, 201):
        return jsonify({"error": "Erro ao criar sessão", "detail": resp.text}), 500

    sessao = resp.json()
    if isinstance(sessao, list):
        sessao = sessao[0]

    sessao_id = sessao["id"]

    # Gera primeira mensagem do assistente (saudação + primeira pergunta)
    try:
        resp_claude = client.messages.create(
            model="claude-sonnet-4-6",
            max_tokens=512,
            system=SYSTEM_ENTREVISTA,
            messages=[{"role": "user", "content": "Olá, quero criar uma VSL."}]
        )
        primeira_mensagem = resp_claude.content[0].text
    except Exception as e:
        primeira_mensagem = "Olá! Sou seu especialista em VSL. Vou te guiar para criar um roteiro poderoso. Vamos começar: qual é o nome do seu produto ou serviço?"

    # Salva a mensagem inicial no banco
    salvar_mensagem(sessao_id, "user", "Olá, quero criar uma VSL.")
    salvar_mensagem(sessao_id, "assistant", primeira_mensagem)

    return jsonify({
        "sessao_id": sessao_id,
        "primeira_mensagem": primeira_mensagem
    })


@app.route("/api/chat", methods=["POST"])
def chat():
    """Processa mensagem e retorna resposta com streaming SSE."""
    data = request.get_json()
    sessao_id = data.get("sessao_id")
    mensagem_usuario = data.get("mensagem", "").strip()
    token = data.get("token", SUPABASE_SERVICE_KEY)

    if not sessao_id or not mensagem_usuario:
        return jsonify({"error": "sessao_id e mensagem são obrigatórios"}), 400

    # Contexto extra: URLs detectadas automaticamente + arquivos enviados
    contexto_extra = data.get("contexto_extra", "")  # texto já extraído pelo frontend

    # Detecta URLs na mensagem e faz scraping automaticamente
    urls_detectadas = detectar_urls(mensagem_usuario)
    textos_urls = []
    for url in urls_detectadas[:3]:  # máx 3 URLs por mensagem
        texto_url = extrair_texto_url(url)
        if texto_url and not texto_url.startswith("[Erro"):
            textos_urls.append(f"[Conteúdo extraído de {url}]:\n{texto_url}")

    # Monta mensagem enriquecida com contexto
    mensagem_enriquecida = mensagem_usuario
    partes_contexto = []
    if textos_urls:
        partes_contexto.append("\n\n---\n" + "\n\n".join(textos_urls))
    if contexto_extra:
        partes_contexto.append(f"\n\n---\n[Conteúdo do arquivo enviado]:\n{contexto_extra}")
    if partes_contexto:
        mensagem_enriquecida += "".join(partes_contexto)

    # Busca histórico
    mensagens_db = get_mensagens(sessao_id)

    # Verifica se deve gerar VSL
    modo_geracao = deve_gerar_vsl(mensagens_db)

    # Salva mensagem do usuário (texto original, sem o contexto injetado)
    salvar_mensagem(sessao_id, "user", mensagem_usuario)

    # Monta histórico para o Claude
    history = []
    for msg in mensagens_db:
        history.append({
            "role": msg["role"],
            "content": msg["content"]
        })
    history.append({"role": "user", "content": mensagem_enriquecida})

    # Escolhe system prompt
    if modo_geracao:
        system_prompt = SYSTEM_GERACAO
        # Atualiza status para gerando
        atualizar_status_sessao(sessao_id, "gerando")
    else:
        system_prompt = SYSTEM_ENTREVISTA

    def generate():
        full_response = ""
        is_first_exchange = len(mensagens_db) <= 2

        try:
            with client.messages.stream(
                model="claude-sonnet-4-6",
                max_tokens=8192 if modo_geracao else 1024,
                system=system_prompt,
                messages=history
            ) as stream:
                for text in stream.text_stream:
                    full_response += text
                    yield f"data: {json.dumps({'text': text})}\n\n"
        except Exception as e:
            yield f"data: {json.dumps({'error': str(e)})}\n\n"
            return

        # Salva resposta completa
        salvar_mensagem(sessao_id, "assistant", full_response)

        # Detecta se a resposta indica geração de VSL
        if "GERAR_VSL" in full_response and not modo_geracao:
            # Marca sessão como gerando
            atualizar_status_sessao(sessao_id, "gerando")

        # Se estava gerando, marca como concluída
        if modo_geracao:
            atualizar_status_sessao(sessao_id, "concluida")

        # Atualiza título com nome do produto (segunda troca)
        if is_first_exchange:
            # Tenta extrair produto do histórico
            pass
        elif len(mensagens_db) == 2:
            # Primeira resposta do usuário provavelmente é o nome do produto
            titulo_candidato = mensagem_usuario[:60]
            if titulo_candidato:
                atualizar_titulo_sessao(sessao_id, f"VSL - {titulo_candidato}")

        yield f"data: {json.dumps({'done': True, 'modo_geracao': modo_geracao})}\n\n"

    return Response(
        generate(),
        mimetype="text/event-stream",
        headers={
            "Cache-Control": "no-cache",
            "X-Accel-Buffering": "no",
            "Connection": "keep-alive"
        }
    )


@app.route("/api/sessao/<sessao_id>/mensagens", methods=["GET"])
def listar_mensagens(sessao_id):
    """Lista mensagens de uma sessão."""
    mensagens = get_mensagens(sessao_id)
    return jsonify(mensagens)


@app.route("/api/sessao/<sessao_id>", methods=["DELETE"])
def deletar_sessao(sessao_id):
    """Deleta sessão e suas mensagens."""
    resp = supa_delete(
        f"sessoes_vsl?id=eq.{sessao_id}",
        token=SUPABASE_SERVICE_KEY
    )
    if resp.status_code in (200, 204):
        return jsonify({"ok": True})
    return jsonify({"error": resp.text}), 500


@app.route("/api/sessao/<sessao_id>/titulo", methods=["PATCH"])
def renomear_sessao(sessao_id):
    """Renomeia uma sessão."""
    data = request.get_json(force=True) or {}
    titulo = (data.get("titulo") or "").strip()
    if not titulo:
        return jsonify({"error": "Título não pode ser vazio"}), 400
    resp = requests.patch(
        f"{SUPABASE_URL}/rest/v1/sessoes_vsl?id=eq.{sessao_id}",
        headers={
            "apikey": SUPABASE_SERVICE_KEY,
            "Authorization": f"Bearer {SUPABASE_SERVICE_KEY}",
            "Content-Type": "application/json",
            "Prefer": "return=representation"
        },
        json={"titulo": titulo},
        timeout=10
    )
    if resp.status_code in (200, 204):
        return jsonify({"ok": True, "titulo": titulo})
    return jsonify({"error": resp.text}), 500


@app.route("/api/sessoes/<usuario_id>", methods=["GET"])
def listar_sessoes(usuario_id):
    """Lista sessões de um usuário."""
    resp = supa_get(
        f"sessoes_vsl?usuario_id=eq.{usuario_id}&order=atualizado_em.desc",
        token=SUPABASE_SERVICE_KEY
    )
    if resp.status_code == 200:
        return jsonify(resp.json())
    return jsonify([])


if __name__ == "__main__":
    print("VSL Backend rodando na porta 5053...")
    app.run(host="0.0.0.0", port=5053, debug=False)
