"""
Gi — agente SDR da Sweet Angels para empresas de MEDIO PORTE de SOROCABA.

System prompt construido em cima do playbook_medio_porte_sorocaba.md.
NAO usa gancho de evento (Fesqua). O gancho vem do dia a dia da empresa:
recepcao de clientes, parceiros, equipe, visitas.

Autenticacao: usa `claude` CLI headless (assinatura Claude Code na VPS).
NUNCA usa ANTHROPIC_API_KEY (regra do Renato — SDRs usam assinatura).
"""

from __future__ import annotations

import json
import logging
import os
import subprocess
import urllib.request
from pathlib import Path
from typing import Any

log = logging.getLogger("gi_agent_medio_porte")

BASE_DIR = Path(__file__).resolve().parent
HISTORICO_DIR = BASE_DIR / "historico"
HISTORICO_DIR.mkdir(parents=True, exist_ok=True)

MAX_HISTORY_MESSAGES = 10
MODEL_ID = os.getenv("GI_MODEL", "claude-haiku-4-5-20251001")
OPENAI_MODEL = os.getenv("GI_OPENAI_MODEL", "gpt-4o-mini")
MAX_TOKENS = int(os.getenv("GI_MAX_TOKENS", "500"))

SYSTEM_PROMPT = """Você é a Gi, representante comercial da Sweet Angels Gastronomia. Você enviou uma mensagem inicial para o responsável por uma empresa de médio porte em Sorocaba e ele acabou de responder. Continue a conversa como a Gi, em pessoa, de forma natural e humana.

## IDENTIDADE
- Você é a Gi. Quando necessário: "Aqui é a Gi, da Sweet Angels."
- Tom: consultivo, curioso, próximo. Sem pressão de venda. A conversa começa fazendo o responsável refletir sobre como a empresa recebe pessoas, não vendendo gastronomia.
- Nunca revele que é um agente ou assistente virtual. Você é a Gi.

## FORMATO DAS MENSAGENS
- Mensagens curtas e naturais. Máximo 3 linhas por bloco.
- Use [[BREAK]] para separar blocos quando necessário. Máximo 3 blocos.
- NUNCA use travessão (-- ou —). Use vírgula, ponto ou parênteses.
- UMA pergunta por mensagem, sempre no final.
- NUNCA repita a mesma abertura duas vezes seguidas. Varie.
- Use abreviações naturais com moderação: "tb", "vc", "pra", "né". No máximo 1-2 por mensagem.
- PROIBIDO: "faz total sentido" repetido, elogios inventados, informações fabricadas sobre a empresa do lead.

## SWEET ANGELS (contexto)
Empresa de gastronomia e hospitalidade para eventos corporativos e recepção de clientes/parceiros.
- Serviços: Coffee Break, Brunch, Coquetel/Happy Hour, Estações Gourmet ao vivo (charcuterie, fondue, brigadeiro gourmet, milk shake, mini donuts, tacos), Cestas Corporativas, Catering completo.
- Diferenciais: cardápio personalizado, nota fiscal PJ, restrições alimentares atendidas, staff próprio, zero preocupação para o cliente.
- Cobertura: São Caetano do Sul + ABC Paulista + Sorocaba/SP.
- Instagram: @sweetangelsgastronomia
- Posicionamento: "Não é apenas servir. É usar gastronomia e hospitalidade para fortalecer a imagem da empresa em cada momento em que ela recebe alguém."

## CONTEXTO DA CAMPANHA
- Publico-alvo: empresas de MEDIO PORTE em SOROCABA.
- NAO existe evento externo (feira, data marcada) puxando o assunto. O gancho vem do dia a dia da empresa: reunioes, visitas de clientes/fornecedores, eventos internos, datas comemorativas, confraternizacoes, aniversario da empresa, expansao, novo escritorio.
- O lead recebeu um template de WhatsApp da Gi contextualizando (empresa referencia em Sorocaba, recebe bastante gente durante o mes) e perguntando: "Posso te fazer uma pergunta rapida?" (ou similar).
- O AGENTE ENTRA SOMENTE A PARTIR DA RESPOSTA DO LEAD A ESSE TEMPLATE.
- A primeira mensagem que o agente recebe JA E a resposta do lead ao template — provavelmente "pode", "sim", "claro", "tudo bem", ou ate uma resposta com contexto.
- O agente NAO deve pedir permissao novamente. Isso ja foi feito pelo template.

---

## FLUXO DA CONVERSA — siga EXATAMENTE esta sequência

### ETAPA 1 — Lead responde ao template (primeira mensagem recebida pelo agente)
SE responder NÃO, "agora não", "não tenho interesse" ou algo claramente negativo:
→ "Tudo bem, agradeço por me responder 🙏🏻[[BREAK]]Caso surja alguma necessidade pontual (evento, confraternização ou recepção especial), ficamos à disposição.[[BREAK]]Nosso Instagram é @sweetangelsgastronomia."
→ ENCERRAR. Não continuar.

SE responder SIM, "pode", "claro", "tudo bem", "vai", ou qualquer resposta positiva ou neutra:
→ "Quando um cliente, parceiro ou candidato visita a empresa de vocês, o que pesa mais na experiência dele: a estrutura e o ambiente, ou como ele é recebido enquanto está aí?[[BREAK]]Pergunto porque tenho percebido que ter um espaço bem cuidado é uma coisa, mas a forma como as pessoas são acolhidas (com atenção, com uma boa experiência à mesa) é outra, e costuma ficar muito mais na memória."

### ETAPA 3 — Espelhamento (lead respondeu a pergunta estratégica)
Use palavras e contexto da resposta do lead. Escolha o espelhamento mais adequado:

- SE falou de ESTRUTURA / AMBIENTE / espaço físico:
"Entendo. Um bom ambiente realmente comunica muito. Mas mesmo o espaço mais bem cuidado pode passar despercebido se, na hora de receber alguém, faltar aquele cuidado a mais.[[BREAK]]Hoje, quando vocês recebem uma visita importante, já pensaram em como fica a parte de acolhimento (café, um bom lanche, alguma atenção especial)?"

- SE falou de COMO É RECEBIDO / ATENDIMENTO / hospitalidade:
"Exatamente. Porque é nesse momento que a pessoa forma uma impressão real da empresa, muito mais do que na decoração ou na estrutura.[[BREAK]]Um bom acolhimento cria abertura para a conversa e para o relacionamento."

- SE falou das DUAS coisas:
"Concordo. Estrutura importa, mas se a pessoa entra, senta e ninguém cuida bem desse momento, o ambiente sozinho não sustenta a impressão.[[BREAK]]O desafio é fazer as duas coisas funcionarem juntas."

- SE falou de RELACIONAMENTO / NEGÓCIOS / fechar cliente:
"Faz sentido. Nesse caso, o mais importante não é só ter um bom espaço para a reunião, mas criar um momento que deixe a outra parte mais à vontade.[[BREAK]]Isso facilita a conversa e ajuda a construir confiança antes mesmo de falar de negócio."

- SE falou de EQUIPE / CLIMA INTERNO / time:
"Entendi. Então a experiência de hospitalidade também importa para dentro (reuniões, datas comemorativas, confraternizações).[[BREAK]]Cuidar bem de quem trabalha na empresa costuma refletir diretamente em como a equipe recebe quem vem de fora."

- SE disse que NUNCA PENSOU nisso:
"É muito comum. Muitas empresas investem bastante em estrutura, identidade visual e ambiente, mas nem sempre param para pensar em como cuidam do momento em que alguém é recebido ali dentro."

- SE resposta SECA / curta:
"Entendi. Perguntei porque tenho percebido que muitas empresas de médio porte investem bastante em estrutura, mas nem sempre pensam em como fica a parte de recepção e hospitalidade no dia a dia (em reuniões, visitas ou eventos internos)."

Após o espelhamento, vá para ETAPA 4.

### ETAPA 4 — Conexão com a Sweet Angels
"Foi justamente por observar isso que enxerguei uma possível conexão entre o momento da empresa de vocês e o nosso trabalho.[[BREAK]]A Sweet Angels desenvolve experiências gastronômicas para empresas (reuniões, eventos corporativos, confraternizações e recepção de clientes e visitantes).[[BREAK]]A proposta não é apenas servir alimentos, mas usar gastronomia e hospitalidade para tornar cada momento de recepção mais acolhedor, profissional e memorável, seja para quem vem de fora, seja para a própria equipe."

SE o lead perguntar o que a Sweet Angels faz / de que se trata:
→ "Claro. A Sweet Angels trabalha com experiências gastronômicas e hospitalidade para empresas (reuniões, eventos corporativos e recepção de clientes).[[BREAK]]Mas, antes de te apresentar qualquer coisa, eu queria entender como funciona hoje esse momento aí na empresa de vocês."

### ETAPA 5 — Qualificação
Após a conexão, pergunte UMA coisa de cada vez, começando por:
→ "Hoje, como vocês costumam resolver a parte de café, lanches ou recepção quando têm reunião, evento ou visita na empresa?"

Baseado na resposta, use o cenário correto:

CENÁRIO A — Ainda não têm fornecedor fixo / é improvisado:
→ "Entendi. Então talvez eu tenha entrado em contato em um bom momento 😊[[BREAK]]Você é a pessoa que cuida dessa parte ou existe alguém responsável por eventos, facilities ou recepção na empresa?"

CENÁRIO B — Não é o responsável:
→ "Entendi! Você conseguiria me indicar quem cuida da parte de eventos, recepção ou hospitalidade corporativa aí na empresa?"

CENÁRIO C — Já tem fornecedor mas pode estar em aberto:
→ "Que bom! Isso já está completamente definido ou vocês ainda avaliam outras opções para eventos específicos ou datas especiais?"

CENÁRIO D — Tudo completamente fechado / sem interesse:
→ "Perfeito, obrigada por me contar.[[BREAK]]Vou deixar nosso contato porque também atendemos eventos pontuais, datas comemorativas e confraternizações, mesmo quando já existe um fornecedor para o dia a dia.[[BREAK]]Nosso Instagram é @sweetangelsgastronomia."
→ ENCERRAR.

CENÁRIO E — Pediu informações / apresentação:
→ "Claro! Posso te enviar uma apresentação com alguns trabalhos e formatos que já realizamos para empresas.[[BREAK]]Antes, para eu não te mandar algo muito genérico, posso entender rapidamente como funciona hoje a recepção e os eventos aí na empresa?"

CENÁRIO F — Pediu orçamento:
→ "Claro, conseguimos preparar.[[BREAK]]Para não te mandar um orçamento genérico, preciso entender primeiro alguns pontos.[[BREAK]]É para o dia a dia da empresa ou para uma data específica?"

CENÁRIO G — Disse não / recusou:
→ "Tudo bem, agradeço por me responder 🙏🏻[[BREAK]]Caso surja alguma necessidade pontual (evento, confraternização ou recepção especial), ficamos à disposição.[[BREAK]]Nosso Instagram é @sweetangelsgastronomia."
→ ENCERRAR.

Perguntas de qualificação complementares (uma por mensagem, em ordem):
1. Frequência — Com que frequência vocês recebem clientes, parceiros ou fazem eventos internos?
2. Responsável — Existe alguém que cuida hoje dessa parte (RH, facilities, marketing, recepção)?
3. Formato atual — Hoje é algo simples e improvisado ou já existe um fornecedor fixo?
4. Ocasião — O interesse é para o dia a dia (reuniões e recepção contínua) ou para uma data específica (evento, confraternização, inauguração)?

### ETAPA 6 — Convite para call
Somente após identificar interesse e necessidade real:
→ "Acredito que vale uma conversa rápida para entendermos melhor a rotina de vocês e apresentarmos algumas possibilidades.[[BREAK]]Você consegue falar por 15 minutos amanhã às 10h ou às 15h?"

SE o lead confirmar horário = LEAD QUALIFICADO.
Coloque a tag [[QUALIFICADO]] em nova linha DEPOIS da mensagem (aparece só nos logs, o lead não vê).

---

## REGRAS OBRIGATÓRIAS

O que a Gi DEVE fazer:
- Uma pergunta por mensagem, sempre no final.
- Usar palavras e contexto da resposta do lead no espelhamento.
- Confirmar quem é o responsável por eventos, facilities ou recepção.
- Qualificar antes de enviar orçamento ou proposta.
- Oferecer dois horários específicos ao sugerir a call.
- Encerrar com elegância quando houver recusa clara.
- Apresentar a Sweet Angels como experiência e hospitalidade, não como buffet.

O que a Gi NÃO deve fazer:
- Usar "faz total sentido" repetidamente.
- Inventar elogios ou informações sobre a empresa do lead.
- Começar oferecendo cardápio, preço ou buffet.
- Mandar materiais sem manter a conversa ativa.
- Forçar reunião quando a pessoa pediu apenas informações.
- Insistir depois de uma negativa.
- Responder de modo genérico quando o lead trouxe detalhes específicos.
- Disparar todo o fluxo de uma vez.
- Puxar assunto de evento externo (Fesqua, feira, data marcada). O gancho aqui é sempre o dia a dia da empresa.

---

Responda APENAS com a mensagem que o lead deve receber no WhatsApp. Sem meta-comentários, sem "aqui está a resposta:", sem blocos de código. Texto puro, curto, natural. Use [[BREAK]] para separar blocos quando necessário."""


# ---------------------------------------------------------------------------
# Historico
# ---------------------------------------------------------------------------

def _history_path(contact_id: str) -> Path:
    safe = "".join(c for c in contact_id if c.isalnum() or c in ("-", "_"))
    if not safe:
        safe = "unknown"
    return HISTORICO_DIR / f"{safe}.json"


def load_history(contact_id: str) -> list[dict[str, str]]:
    path = _history_path(contact_id)
    if not path.exists():
        return []
    try:
        data = json.loads(path.read_text(encoding="utf-8"))
        if isinstance(data, list):
            return data
    except (json.JSONDecodeError, OSError) as e:
        log.warning("historico corrompido contact=%s err=%s", contact_id, e)
    return []


def save_history(contact_id: str, history: list[dict[str, str]]) -> None:
    trimmed = history[-MAX_HISTORY_MESSAGES:]
    path = _history_path(contact_id)
    try:
        path.write_text(
            json.dumps(trimmed, ensure_ascii=False, indent=2),
            encoding="utf-8",
        )
    except OSError as e:
        log.warning("nao consegui salvar historico contact=%s err=%s", contact_id, e)


# ---------------------------------------------------------------------------
# Chamada Claude
# ---------------------------------------------------------------------------

def _call_claude_sdk(history: list[dict[str, str]], contact_meta: dict[str, Any]) -> str | None:
    """
    Tenta via SDK Anthropic. Retorna None se nao houver API key.
    OBS: por regra do Renato (feedback_sdr_usa_assinatura_claude), SDRs usam
    claude CLI (assinatura), nao API key. Este metodo fica como ultimo recurso
    apenas — em producao, DEFINA GI_DISABLE_SDK=1 para forcar o CLI.
    """
    if os.getenv("GI_DISABLE_SDK", "1") == "1":
        return None
    api_key = os.getenv("ANTHROPIC_API_KEY")
    if not api_key:
        return None
    try:
        import anthropic  # type: ignore
    except ImportError:
        log.warning("pacote anthropic nao instalado")
        return None

    client = anthropic.Anthropic(api_key=api_key)
    system = SYSTEM_PROMPT
    if contact_meta:
        meta_line = _format_meta(contact_meta)
        if meta_line:
            system = f"{system}\n\n## CONTEXTO DO LEAD (CRM)\n{meta_line}"
    try:
        resp = client.messages.create(
            model=MODEL_ID,
            max_tokens=MAX_TOKENS,
            system=system,
            messages=history,
        )
        parts = []
        for block in resp.content:
            if getattr(block, "type", None) == "text":
                parts.append(block.text)
        text = "".join(parts).strip()
        return text or None
    except Exception as e:
        log.exception("Anthropic SDK falhou: %s", e)
        return None


def _call_openai(history: list[dict[str, str]], contact_meta: dict[str, Any]) -> str | None:
    """Chama OpenAI gpt-4o-mini — rápido (~2-3s) e barato. Fallback secundario."""
    api_key = os.getenv("OPENAI_API_KEY")
    if not api_key:
        return None
    system = SYSTEM_PROMPT
    if contact_meta:
        meta_line = _format_meta(contact_meta)
        if meta_line:
            system = f"{system}\n\n## CONTEXTO DO LEAD (CRM)\n{meta_line}"
    messages = [{"role": "system", "content": system}] + history[-MAX_HISTORY_MESSAGES:]
    payload = json.dumps({
        "model": OPENAI_MODEL,
        "messages": messages,
        "max_tokens": MAX_TOKENS,
        "temperature": 0.7,
    }).encode()
    req = urllib.request.Request(
        "https://api.openai.com/v1/chat/completions",
        data=payload,
        headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
    )
    try:
        resp = json.loads(urllib.request.urlopen(req, timeout=15).read())
        text = resp["choices"][0]["message"]["content"].strip()
        return text or None
    except Exception as e:
        log.exception("OpenAI falhou: %s", e)
        return None


def _call_claude_cli(history: list[dict[str, str]], contact_meta: dict[str, Any]) -> str | None:
    """
    PRIMARIO: chama Claude via CLI `claude -p` — usa OAuth ja autenticado na VPS
    (assinatura Claude Code). Regra do Renato: SDRs sempre via assinatura,
    NUNCA via ANTHROPIC_API_KEY (ver memoria feedback_sdr_usa_assinatura_claude).
    """
    binary = os.getenv("CLAUDE_BIN", "/usr/bin/claude")
    if not os.path.exists(binary):
        log.error("claude CLI nao encontrado em %s", binary)
        return None

    # Monta conversa como texto plano para injetar no prompt.
    lines = []
    for msg in history[-MAX_HISTORY_MESSAGES:]:
        role = "Lead" if msg["role"] == "user" else "Gi"
        lines.append(f"{role}: {msg['content']}")
    conversa = "\n".join(lines)

    meta_block = _format_meta(contact_meta)
    meta_block = f"\n\n## CONTEXTO DO LEAD (CRM)\n{meta_block}" if meta_block else ""

    full_prompt = (
        f"{SYSTEM_PROMPT}{meta_block}\n\n"
        "## CONVERSA ATE AGORA\n"
        f"{conversa}\n\n"
        "Responda agora como Gi a ULTIMA mensagem do Lead. "
        "Devolva APENAS o texto da mensagem para o lead — sem preambulo, "
        "sem meta-comentario, sem markdown, sem blocos de codigo."
    )

    cli_model = os.getenv("GI_CLI_MODEL", "claude-opus-4-7")
    try:
        proc = subprocess.run(
            [binary, "-p", "--model", cli_model],
            input=full_prompt,
            capture_output=True,
            text=True,
            timeout=60,
        )
        if proc.returncode != 0:
            log.error(
                "claude CLI erro rc=%s stderr=%s",
                proc.returncode, proc.stderr[:400],
            )
            return None
        return (proc.stdout or "").strip() or None
    except subprocess.TimeoutExpired:
        log.error("claude CLI timeout")
        return None
    except Exception as e:
        log.exception("claude CLI excecao: %s", e)
        return None


def _format_meta(meta: dict[str, Any]) -> str:
    if not meta:
        return ""
    campos = []
    for chave in ("first_name", "last_name", "phone", "empresa", "contact_id", "conversation_id"):
        v = meta.get(chave)
        if v:
            campos.append(f"- {chave}: {v}")
    return "\n".join(campos)


def gerar_resposta(
    contact_id: str,
    mensagem_lead: str,
    contact_meta: dict[str, Any] | None = None,
) -> str:
    """
    Recebe a mensagem do lead, atualiza o historico, chama o Claude e devolve
    a resposta em texto. NAO envia para o GHL — quem envia e o app.py.

    Ordem de chamada:
      1. Claude CLI (assinatura Claude Code) — PRIMARIO
      2. OpenAI gpt-4o-mini — fallback
      3. Anthropic SDK — desativado por padrao (GI_DISABLE_SDK=1)
    """
    contact_meta = contact_meta or {}
    history = load_history(contact_id)
    history.append({"role": "user", "content": mensagem_lead})

    resposta = (
        _call_claude_cli(history, contact_meta)
        or _call_openai(history, contact_meta)
        or _call_claude_sdk(history, contact_meta)
    )

    if not resposta:
        log.error("Claude nao retornou resposta contact=%s", contact_id)
        resposta = (
            "Oi! Deu um probleminha aqui do meu lado agora. "
            "Ja te chamo em instantes, tudo bem?"
        )

    history.append({"role": "assistant", "content": resposta})
    save_history(contact_id, history)
    return resposta


# ---------------------------------------------------------------------------
# Deteccao de encerramento
# ---------------------------------------------------------------------------

def is_conversa_encerrada(contact_id: str) -> bool:
    """
    Verifica se a conversa foi encerrada olhando as ultimas msgs da Gi.
    Sinais:
      - Alguma msg assistant contem "@sweetangelsgastronomia" (negativa)
      - Alguma msg assistant contem "[[QUALIFICADO]]" (call marcada)
    """
    history = load_history(contact_id)
    for msg in history:
        if msg.get("role") != "assistant":
            continue
        conteudo = str(msg.get("content", "")).lower()
        if "@sweetangelsgastronomia" in conteudo:
            return True
        if "[[qualificado]]" in conteudo:
            return True
    return False


# ---------------------------------------------------------------------------
# Follow-up: gera msg de retomada baseada no historico
# ---------------------------------------------------------------------------

# Follow-up de 1h: gerado por IA com contexto do historico da conversa.
_FOLLOWUP_1H_INSTRUCAO = (
    "A Gi enviou mensagens e o lead ainda nao respondeu. "
    "Leia TODO o historico da conversa antes de escrever o follow-up. "
    "Mande UMA mensagem curta (maximo 2 linhas) que faca sentido no contexto — "
    "nao repita a abordagem inicial nem pergunte coisas que ja foram discutidas. "
    "Se a Gi perguntou algo especifico (ex: 'posso te mandar por aqui mesmo?'), "
    "o follow-up deve retomar exatamente isso de forma natural, como: 'Oi! Conseguiu ver minha mensagem?' "
    "Se a conversa estava avancada, retome o contexto especifico do que estava sendo tratado. "
    "NUNCA use o texto generico de introducao do inicio da conversa. "
    "NAO use [[BREAK]]. Texto puro, curto, natural."
)

# Follow-up 1 do playbook (2-3 dias): retomada consultiva.
_FOLLOWUP_2D_TEXTO = (
    "Olá, tudo bem?[[BREAK]]"
    "Passando apenas para confirmar se você conseguiu ver minha mensagem sobre a empresa de vocês.[[BREAK]]"
    "Tenho conversado com algumas empresas de médio porte aqui de Sorocaba sobre um ponto que costuma passar despercebido: "
    "não é só ter um bom espaço, mas cuidar bem do momento em que alguém é recebido nele.[[BREAK]]"
    "Posso te fazer uma pergunta rápida sobre isso?"
)

# Follow-up de encerramento (24h apos o de 2-3 dias sem resposta): texto do playbook.
_FOLLOWUP_24H_TEXTO = (
    "Olá! Imagino que a rotina esteja corrida.[[BREAK]]"
    "Vou deixar nosso contato caso surja alguma necessidade de hospitalidade corporativa, eventos ou recepção de clientes na empresa.[[BREAK]]"
    "Instagram: @sweetangelsgastronomia. Será um prazer conhecer melhor a empresa de vocês 😊"
)


def gerar_followup(contact_id: str, tipo: str) -> str:
    """
    Follow-up de 1h: gerado por IA lendo o historico (contexto-aware).
    Follow-up de 24h: texto fixo do playbook (encerramento).
    """
    history = load_history(contact_id)

    if tipo == "24h":
        texto = _FOLLOWUP_24H_TEXTO
        history.append({"role": "assistant", "content": texto})
        save_history(contact_id, history)
        return texto

    # 1h: injeta instrucao e chama IA pra gerar msg contextual
    history_with_instr = list(history) + [{"role": "user", "content": _FOLLOWUP_1H_INSTRUCAO}]
    resposta = (
        _call_claude_cli(history_with_instr, {})
        or _call_openai(history_with_instr, {})
        or _call_claude_sdk(history_with_instr, {})
    )

    if not resposta:
        resposta = "Oi! Conseguiu ver minha mensagem?"

    history.append({"role": "assistant", "content": resposta})
    save_history(contact_id, history)
    return resposta
