"""Persistencia simples dos dados recebidos pelo Webhook da Rubeus.

Os dados chegam por POST em formato JSON (veja https://docs.rubeus.com.br/webhook/)
e sao armazenados em arquivos JSON dentro de uma pasta (RUBEUS_WEBHOOK_DIR),
indexados pelo "id" de cada item. Assim, quando a Rubeus reenvia um contato ou
registro (atualizacao), o item e simplesmente sobrescrito mantendo a base sempre
atualizada.

Arquivos gerados:
    <dir>/contatos.json   -> { "<id>": { ...contato cru do webhook... } }
    <dir>/registros.json  -> { "<id>": { ...registro de processo cru... } }
    <dir>/atividades.json -> { "<id>": { ...atividade... } }
    <dir>/eventos.json    -> { "<id>": { ...evento... } }
"""
from __future__ import annotations

import json
import os
import tempfile
import threading
from datetime import datetime
from pathlib import Path

ARQUIVOS = {
    "contato": "contatos.json",
    "registro": "registros.json",
    "atividade": "atividades.json",
    "evento": "eventos.json",
}


class WebhookStore:
    """Armazena os itens recebidos pelo webhook em arquivos JSON por tipo."""

    def __init__(self, diretorio: str | Path):
        self.dir = Path(diretorio)
        self.dir.mkdir(parents=True, exist_ok=True)
        self._lock = threading.Lock()

    # ------------------------------------------------------------------ #
    # IO de baixo nivel
    # ------------------------------------------------------------------ #
    def _caminho(self, tipo: str) -> Path:
        nome = ARQUIVOS.get(tipo, f"{tipo}.json")
        return self.dir / nome

    def _ler(self, tipo: str) -> dict:
        caminho = self._caminho(tipo)
        if not caminho.exists():
            return {}
        try:
            return json.loads(caminho.read_text(encoding="utf-8")) or {}
        except (ValueError, OSError):
            return {}

    def _escrever(self, tipo: str, dados: dict) -> None:
        """Escrita atomica (arquivo temporario + replace) para evitar corrupcao."""
        caminho = self._caminho(tipo)
        fd, tmp = tempfile.mkstemp(dir=str(self.dir), suffix=".tmp")
        try:
            with os.fdopen(fd, "w", encoding="utf-8") as fh:
                json.dump(dados, fh, ensure_ascii=False, indent=2)
            os.replace(tmp, caminho)
        finally:
            if os.path.exists(tmp):
                os.remove(tmp)

    # ------------------------------------------------------------------ #
    # API publica
    # ------------------------------------------------------------------ #
    def salvar_itens(self, tipo: str, itens: list[dict]) -> int:
        """Salva/atualiza uma lista de itens do mesmo tipo. Retorna quantos."""
        if not itens:
            return 0
        gravados = 0
        with self._lock:
            base = self._ler(tipo)
            for item in itens:
                if not isinstance(item, dict):
                    continue
                chave = str(item.get("id") or item.get("codigo") or "")
                if not chave:
                    # Sem id: usa um timestamp para nao perder o dado.
                    chave = datetime.now().strftime("%Y%m%d%H%M%S%f")
                item["_recebido_em"] = datetime.now().isoformat(timespec="seconds")
                base[chave] = item
                gravados += 1
            self._escrever(tipo, base)
        return gravados

    def carregar(self, tipo: str) -> dict:
        """Retorna o dicionario {id: item} de um tipo."""
        with self._lock:
            return self._ler(tipo)

    def contagens(self) -> dict[str, int]:
        """Retorna a quantidade de itens armazenados por tipo."""
        return {tipo: len(self._ler(tipo)) for tipo in ARQUIVOS}
