"""
DOOBAT - Service d'authentification
Association Telegram ↔ Odoo et gestion des rôles.
Copyright 2026 Vincent Gallet - Vincesoft
"""

import json
import logging
import os
from configparser import ConfigParser
from typing import Optional

logger = logging.getLogger("doobat.auth")

CONTACTS_FILE = "data/telegram_contacts.json"


class AuthService:
    """
    Gère l'association entre les identifiants Telegram (chat_id)
    et les partenaires Odoo (partner_id).
    Persiste dans data/telegram_contacts.json.
    """

    def __init__(self, config: ConfigParser):
        self._contacts_file = config.get(
            "DATA", "contacts_file", fallback=CONTACTS_FILE
        )
        self._contacts: dict[str, int | dict] = {}
        self._load()
        logger.info(
            f"AuthService initialisé, {len(self._contacts)} association(s) chargée(s)."
        )

    def _load(self) -> None:
        """Charge les associations depuis le fichier JSON."""
        os.makedirs(os.path.dirname(self._contacts_file), exist_ok=True)
        if os.path.exists(self._contacts_file):
            try:
                with open(self._contacts_file, "r", encoding="utf-8") as f:
                    data = json.load(f)
                    # Clé = str(chat_id), valeur = int(partner_id)
                    self._contacts = {}
                    for key, value in data.items():
                        if not str(key).lstrip("-").isdigit():
                            continue
                        if str(value).isdigit():
                            self._contacts[str(key)] = int(value)
                        elif (
                            isinstance(value, dict)
                            and str(value.get("partner_id", "")).isdigit()
                        ):
                            self._contacts[str(key)] = {
                                "partner_id": int(value["partner_id"]),
                                "phone": str(value.get("phone", "")),
                            }
            except (json.JSONDecodeError, ValueError) as e:
                logger.error(f"Erreur lecture {self._contacts_file} : {e}")
                self._contacts = {}
        else:
            self._contacts = {}
            self._save()

    def _save(self) -> None:
        """Persiste les associations dans le fichier JSON."""
        try:
            os.makedirs(os.path.dirname(self._contacts_file), exist_ok=True)
            tmp_file = self._contacts_file + ".tmp"
            with open(tmp_file, "w", encoding="utf-8") as f:
                json.dump(self._contacts, f, ensure_ascii=False, indent=2)
            os.replace(tmp_file, self._contacts_file)
        except OSError as e:
            logger.error(f"Erreur sauvegarde associations Telegram : {e}")

    def find_partner_by_telegram(self, chat_id: int) -> Optional[int]:
        """
        Retourne le partner_id Odoo associé à un chat_id Telegram,
        ou None si non trouvé.
        """
        association = self._contacts.get(str(chat_id))
        partner_id = (
            association.get("partner_id")
            if isinstance(association, dict)
            else association
        )
        if partner_id:
            logger.debug(f"Association Telegram→Odoo : chat_id={chat_id} → partner_id={partner_id}")
        return partner_id

    def get_linked_phone(self, chat_id: int) -> str:
        """Retourne le numero valide lors de l'association, si disponible."""
        association = self._contacts.get(str(chat_id))
        if isinstance(association, dict):
            return str(association.get("phone", ""))
        return ""

    def link_telegram_to_partner(
        self, chat_id: int, partner_id: int, phone: str = ""
    ) -> bool:
        """
        Crée ou met à jour l'association Telegram ↔ Odoo.
        Retourne True si succès.
        """
        if not isinstance(chat_id, int) or not isinstance(partner_id, int):
            logger.warning(f"link_telegram_to_partner : types invalides chat_id={chat_id}, partner_id={partner_id}")
            return False

        self._contacts[str(chat_id)] = (
            {"partner_id": partner_id, "phone": phone}
            if phone
            else partner_id
        )
        self._save()
        logger.info(f"Association créée : Telegram chat_id={chat_id} → Odoo partner_id={partner_id}")
        return True

    def unlink_telegram(self, chat_id: int) -> bool:
        """Supprime l'association pour un chat_id."""
        key = str(chat_id)
        if key in self._contacts:
            del self._contacts[key]
            self._save()
            logger.info(f"Association supprimée pour chat_id={chat_id}")
            return True
        return False

    def list_associations(self) -> dict[str, int | dict]:
        """Retourne toutes les associations (copie défensive)."""
        return dict(self._contacts)
