"""
Gestion des tâches - Module modulaire pour Kuby
Utilise disnake et un stockage JSON par serveur.
"""

import json
import os
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
from typing import Optional, Dict, List, Tuple, Any

# Chemin du fichier de stockage
DATA_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), "data")
TACHES_FILE = os.path.join(DATA_DIR, "taches.json")

# Priorités disponibles
PRIORITES = ["Haute", "Moyenne", "Basse", "Critique", "Faible"]
STATUTS = ["À faire", "En cours", "Terminée", "Annulée"]


def _assurer_dossier():
    """Crée le dossier data/ si inexistant."""
    os.makedirs(DATA_DIR, exist_ok=True)


def _charger_fichier() -> Dict[str, Any]:
    """Charge le fichier taches.json ou retourne une structure vide."""
    _assurer_dossier()
    if not os.path.exists(TACHES_FILE):
        return {"taches": {}, "archive": {}, "settings": {}}
    try:
        with open(TACHES_FILE, "r", encoding="utf-8") as f:
            return json.load(f)
    except (json.JSONDecodeError, FileNotFoundError):
        return {"taches": {}, "archive": {}, "settings": {}}


def _sauvegarder_fichier(data: Dict[str, Any]) -> None:
    """Sauvegarde les données dans taches.json."""
    _assurer_dossier()
    with open(TACHES_FILE, "w", encoding="utf-8") as f:
        json.dump(data, f, indent=4, ensure_ascii=False)


# ============================================================================
# FONCTIONS DE BASE
# ============================================================================

async def charger_taches() -> Dict[str, Any]:
    """
    Charge toutes les tâches depuis le fichier.
    
    Returns:
        Dict avec clés: taches, archive, settings
    """
    return _charger_fichier()


async def sauvegarder_taches(data: Optional[Dict[str, Any]] = None) -> None:
    """
    Sauvegarde les tâches dans le fichier.
    Si data=None, recharge depuis le fichier et sauvegarde (pour rafraîchir).
    """
    if data is None:
        data = _charger_fichier()
    _sauvegarder_fichier(data)


# ============================================================================
# GESTION DES TÂCHES
# ============================================================================

async def ajouter_tache(
    titre: str,
    description: str,
    assigne_id: int,
    priorite: str,
    echeance: str,  # Format: YYYY-MM-DD
    cree_par_id: int,
    serveur_id: int
) -> str:
    """
    Ajoute une nouvelle tâche.
    
    Args:
        titre: Titre de la tâche
        description: Description détaillée
        assigne_id: ID Discord de l'utilisateur assigné
        priorite: Priorité (doit être dans PRIORITES)
        echeance: Date au format YYYY-MM-DD
        cree_par_id: ID Discord du créateur
        serveur_id: ID du serveur (guild)
    
    Returns:
        str: L'ID unique de la tâche créée
    """
    data = _charger_fichier()
    
    # Valider la priorité
    if priorite not in PRIORITES:
        priorite = "Moyenne"
    
    # Générer un ID unique
    tache_id = str(len(data["taches"]) + 1)
    
    # Date actuelle
    now = datetime.now(ZoneInfo("Europe/Paris"))
    
    data["taches"][tache_id] = {
        "titre": titre,
        "description": description,
        "assigne": assigne_id,
        "cree_par": cree_par_id,
        "priorite": priorite,
        "echeance": echeance,
        "statut": "À faire",
        "date_creation": now.strftime("%Y-%m-%d %H:%M:%S"),
        "date_fin": None,
        "serveur_id": serveur_id,
        "archive": False
    }
    
    _sauvegarder_fichier(data)
    return tache_id


async def lister_taches_utilisateur(user_id: int, serveur_id: int) -> Dict[str, Dict[str, Any]]:
    """
    Liste les tâches assignées à un utilisateur sur un serveur.
    
    Args:
        user_id: ID Discord de l'utilisateur
        serveur_id: ID du serveur
    
    Returns:
        Dict des tâches (non archivées) de l'utilisateur
    """
    data = _charger_fichier()
    return {
        tid: tache for tid, tache in data["taches"].items()
        if tache.get("assigne") == user_id 
        and tache.get("serveur_id") == serveur_id
        and not tache.get("archive", False)
    }


async def lister_toutes_taches(serveur_id: int) -> Dict[str, Dict[str, Any]]:
    """
    Liste toutes les tâches (non archivées) d'un serveur.
    
    Args:
        serveur_id: ID du serveur
    
    Returns:
        Dict de toutes les tâches du serveur
    """
    data = _charger_fichier()
    return {
        tid: tache for tid, tache in data["taches"].items()
        if tache.get("serveur_id") == serveur_id
        and not tache.get("archive", False)
    }


async def get_tache(tache_id: str) -> Optional[Dict[str, Any]]:
    """
    Récupère une tâche par son ID.
    
    Args:
        tache_id: ID de la tâche
    
    Returns:
        Dict de la tâche ou None si non trouvée
    """
    data = _charger_fichier()
    return data["taches"].get(tache_id)


async def update_tache_status(tache_id: str, statut: str) -> bool:
    """
    Met à jour le statut d'une tâche.
    
    Args:
        tache_id: ID de la tâche
        statut: Nouveau statut
    
    Returns:
        bool: True si la mise à jour a réussi
    """
    data = _charger_fichier()
    
    if tache_id not in data["taches"]:
        return False
    
    if statut not in STATUTS:
        statut = "À faire"
    
    # Mettre à jour le statut
    data["taches"][tache_id]["statut"] = statut
    
    # Si terminée, enregistrer la date de fin
    if statut == "Terminée":
        now = datetime.now(ZoneInfo("Europe/Paris"))
        data["taches"][tache_id]["date_fin"] = now.strftime("%Y-%m-%d %H:%M:%S")
    else:
        data["taches"][tache_id]["date_fin"] = None
    
    _sauvegarder_fichier(data)
    return True


async def update_tache_priorite(tache_id: str, priorite: str) -> bool:
    """
    Met à jour la priorité d'une tâche.
    
    Args:
        tache_id: ID de la tâche
        priorite: Nouvelle priorité
    
    Returns:
        bool: True si la mise à jour a réussi
    """
    data = _charger_fichier()
    
    if tache_id not in data["taches"]:
        return False
    
    if priorite not in PRIORITES:
        return False
    
    data["taches"][tache_id]["priorite"] = priorite
    _sauvegarder_fichier(data)
    return True


async def supprimer_tache(tache_id: str) -> bool:
    """
    Supprime une tâche (la déplace dans l'archive).
    
    Args:
        tache_id: ID de la tâche
    
    Returns:
        bool: True si la suppression a réussi
    """
    data = _charger_fichier()
    
    if tache_id not in data["taches"]:
        return False
    
    # Archiver la tâche au lieu de la supprimer
    tache = data["taches"].pop(tache_id)
    tache["archive"] = True
    tache["date_archivage"] = datetime.now(ZoneInfo("Europe/Paris")).strftime("%Y-%m-%d %H:%M:%S")
    
    data["archive"][tache_id] = tache
    _sauvegarder_fichier(data)
    return True


# ============================================================================
# FONCTIONS DE RAPPEL
# ============================================================================

async def taches_proches(serveur_id: int, heures_avant: int = 1) -> Dict[str, Dict[str, Any]]:
    """
    Récupère les tâches dont l'échéance est dans X heures.
    
    Args:
        serveur_id: ID du serveur
        heures_avant: Nombre d'heures avant l'échéance (défaut: 1)
    
    Returns:
        Dict des tâches proches de leur échéance
    """
    data = _charger_fichier()
    now = datetime.now(ZoneInfo("Europe/Paris"))
    result = {}
    
    for tid, tache in data["taches"].items():
        if tache.get("serveur_id") != serveur_id or tache.get("archive", False):
            continue
        if tache["statut"] == "Terminée":
            continue
        
        try:
            echeance_date = datetime.strptime(tache["echeance"], "%Y-%m-%d")
            echeance_date = echeance_date.replace(
                hour=9, minute=0, second=0, microsecond=0,
                tzinfo=ZoneInfo("Europe/Paris")
            )
            
            # Calculer la différence
            delta = echeance_date - now
            
            # Si l'échéance est dans X heures ou moins, et pas déjà passée
            if timedelta(0) < delta <= timedelta(hours=heures_avant):
                result[tid] = tache
        except (ValueError, TypeError):
            continue
    
    return result


async def taches_aujourdhui(serveur_id: int) -> Dict[str, Dict[str, Any]]:
    """
    Récupère les tâches dont l'échéance est aujourd'hui.
    
    Args:
        serveur_id: ID du serveur
    
    Returns:
        Dict des tâches d'aujourd'hui
    """
    return await taches_proches(serveur_id, heures_avant=24)


# ============================================================================
# ARCHIVAGE AUTOMATIQUE
# ============================================================================

async def archiver_taches_anciennes(serveur_id: int, jours: int = 30) -> int:
    """
    Archive les tâches terminées depuis plus de X jours.
    
    Args:
        serveur_id: ID du serveur
        jours: Nombre de jours après lequel archiver (défaut: 30)
    
    Returns:
        int: Nombre de tâches archivées
    """
    data = _charger_fichier()
    now = datetime.now(ZoneInfo("Europe/Paris"))
    count = 0
    
    to_archive = []
    for tid, tache in data["taches"].items():
        if tache.get("serveur_id") != serveur_id:
            continue
        if tache.get("statut") != "Terminée":
            continue
        if tache.get("archive", False):
            continue
        
        try:
            fin_date = datetime.strptime(tache["date_fin"], "%Y-%m-%d %H:%M:%S")
            fin_date = fin_date.replace(tzinfo=ZoneInfo("Europe/Paris"))
            
            if (now - fin_date) > timedelta(days=jours):
                to_archive.append(tid)
        except (ValueError, TypeError):
            continue
    
    for tid in to_archive:
        tache = data["taches"].pop(tid)
        tache["archive"] = True
        tache["date_archivage"] = now.strftime("%Y-%m-%d %H:%M:%S")
        data["archive"][tid] = tache
        count += 1
    
    if count > 0:
        _sauvegarder_fichier(data)
    
    return count


# ============================================================================
# CONFIGURATION PAR SERVEUR
# ============================================================================

async def get_taches_settings(serveur_id: int) -> Dict[str, Any]:
    """
    Récupère les paramètres des tâches pour un serveur.
    
    Args:
        serveur_id: ID du serveur
    
    Returns:
        Dict des paramètres (taches_enabled, auto_archive_days, etc.)
    """
    data = _charger_fichier()
    return data["settings"].get(str(serveur_id), {
        "taches_enabled": True,
        "auto_archive_days": 30,
        "notify_channel_id": None
    })


async def set_taches_settings(serveur_id: int, settings: Dict[str, Any]) -> None:
    """
    Met à jour les paramètres des tâches pour un serveur.
    
    Args:
        serveur_id: ID du serveur
        settings: Dict des paramètres à mettre à jour
    """
    data = _charger_fichier()
    
    if str(serveur_id) not in data["settings"]:
        data["settings"][str(serveur_id)] = {}
    
    data["settings"][str(serveur_id)].update(settings)
    _sauvegarder_fichier(data)
