"""Service d'import des vacances scolaires depuis l'API gouvernementale."""
import requests
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
from app_new.extensions import db
from app_new.core.models import CollegeClosure


# API du gouvernement pour les vacances scolaires
API_URL = "https://data.education.gouv.fr/api/explore/v2.1/catalog/datasets/fr-en-calendrier-scolaire/records"


def fetch_vacances_scolaires(zone="A", annee=None):
    """
    Récupère les vacances scolaires depuis l'API gouvernementale.
    
    Args:
        zone: Zone académique (A, B ou C)
        annee: Année scolaire (ex: 2024 pour 2024-2025). Si None, année actuelle.
    
    Returns:
        Liste de dictionnaires avec les vacances
    """
    if annee is None:
        annee = datetime.now().year
    
    # L'API du gouvernement filtre par zone et année
    params = {
        "where": f"zones='Zone {zone}' AND annee_scolaire='{annee}-{annee + 1}'",
        "order_by": "start_date",
        "limit": 100,
    }
    
    try:
        response = requests.get(API_URL, params=params, timeout=30)
        response.raise_for_status()
        data = response.json().get("results", [])
        
        vacances = []
        for item in data:
            start = item.get("start_date")
            end = item.get("end_date")
            description = item.get("description", "Vacances scolaires")
            
            if start and end:
                # Filtrer pour l'année scolaire demandée
                start_date = datetime.fromisoformat(start.replace("Z", "+00:00")).astimezone(ZoneInfo("Europe/Paris"))
                if start_date.year >= annee - 1:
                    raw_end_date = datetime.fromisoformat(end.replace("Z", "+00:00")).astimezone(ZoneInfo("Europe/Paris")).date()
                    # Les fermetures ponctuelles (ex. pont de l'Ascension)
                    # sont représentées par le même début et la même fin.
                    end_date = raw_end_date if raw_end_date == start_date.date() else raw_end_date - timedelta(days=1)
                    # Pour l'agent, le 31 août reste une journée de vacances
                    # (la rentrée des enseignants ne déclenche pas la reprise).
                    is_summer = "grandes vacances" in description.lower() or "vacances d'été" in description.lower()
                    if is_summer and raw_end_date.month == 8:
                        end_date = raw_end_date
                    vacances.append({
                        "start_date": start_date.date(),
                        # L'API indique la date de rentrée comme borne de fin.
                        # Elle ne doit pas être affichée comme un jour de vacances.
                        "end_date": end_date,
                        "description": description,
                        "zone": zone
                    })
        
        # Lorsque l'API fournit plusieurs calendriers (enseignants, élèves),
        # retenir la rentrée la plus tardive : la permanence reste possible
        # jusqu'à la veille de la rentrée des élèves.
        # Une ligne existe par académie et parfois par population. Dédupliquer
        # en conservant la date de rentrée la plus tardive (élèves).
        deduped = {}
        for item in vacances:
            key = (item["description"], item["start_date"])
            if key not in deduped or item["end_date"] > deduped[key]["end_date"]:
                deduped[key] = item
        vacances = list(deduped.values())
        grandes = [item for item in vacances if "grandes vacances" in item["description"].lower() or "vacances d'été" in item["description"].lower()]
        if grandes:
            max_end = max(item["end_date"] for item in grandes)
            for item in grandes:
                item["end_date"] = max_end
        return vacances
    except Exception as e:
        print(f"Erreur lors de la récupération des vacances: {e}")
        return []


def import_vacances_scolaires(zone="A", annee=None, user_id=None):
    """
    Importe les vacances scolaires dans la base de données.
    
    Args:
        zone: Zone académique (A, B ou C)
        annee: Année scolaire
        user_id: ID de l'utilisateur qui importe
    
    Returns:
        (nombre_ajoutees, nombre_ignorees, erreurs)
    """
    vacances = fetch_vacances_scolaires(zone, annee)
    
    if not vacances:
        # Données de fallback si l'API n'est pas accessible
        vacances = get_vacances_fallback(zone, annee)

    # Les périodes importées représentent une seule zone de référence.
    # Lors d'un changement de zone, retirer uniquement les anciennes
    # périodes issues d'un import officiel (jamais les périodes manuelles).
    imported_closures = CollegeClosure.query.filter(
        CollegeClosure.closure_type == "vacances_scolaires",
        CollegeClosure.notes.like("Zone académique % — import officiel"),
    ).all()
    for existing in imported_closures:
        if not (existing.notes or "").startswith(f"Zone académique {zone} "):
            db.session.delete(existing)
    if imported_closures:
        db.session.flush()
    
    ajoutees = 0
    ignorees = 0
    erreurs = []
    
    for vac in vacances:
        # Vérifier si cette fermeture existe déjà
        existing = CollegeClosure.query.filter(
            CollegeClosure.closure_type == "vacances_scolaires",
            CollegeClosure.start_date == vac["start_date"],
            CollegeClosure.end_date == vac["end_date"]
        ).first()
        
        if existing:
            ignorees += 1
            continue
        
        try:
            closure = CollegeClosure(
                name=vac["description"],
                start_date=vac["start_date"],
                end_date=vac["end_date"],
                closure_type="vacances_scolaires",
                work_hours_type="none",
                notes=f"Zone académique {zone} — import officiel",
            )
            db.session.add(closure)
            ajoutees += 1
        except Exception as e:
            erreurs.append(f"{vac['description']}: {str(e)}")
    
    if ajoutees > 0:
        db.session.commit()
    
    return ajoutees, ignorees, erreurs


def get_vacances_fallback(zone, annee):
    """
    Retourne les vacances scolaires par défaut si l'API n'est pas accessible.
    Basé sur le calendrier officiel français.
    """
    from datetime import timedelta
    
    if annee is None:
        annee = datetime.now().year
    
    # Calculer l'année scolaire (2024-2025 pour annee=2024)
    annee_scolaire = f"{annee}-{annee + 1}"
    
    # Vacances standardisées (approximatives, à ajuster selon la zone)
    vacances = [
        # Toussaint
        {
            "start_date": datetime(annee, 10, 19).date(),
            "end_date": datetime(annee, 11, 3).date(),
            "description": f"Vacances de la Toussaint {annee_scolaire}",
            "zone": zone
        },
        # Noël
        {
            "start_date": datetime(annee, 12, 21).date(),
            "end_date": datetime(annee + 1, 1, 6).date(),
            "description": f"Vacances de Noël {annee_scolaire}",
            "zone": zone
        },
        # Hiver (diffère selon la zone)
        {
            "start_date": datetime(annee + 1, 2, 15).date() if zone != "C" else datetime(annee + 1, 2, 22).date(),
            "end_date": datetime(annee + 1, 3, 2).date() if zone != "C" else datetime(annee + 1, 3, 9).date(),
            "description": f"Vacances d'hiver {annee_scolaire}",
            "zone": zone
        },
        # Printemps (diffère selon la zone) - CORRIGÉ: annee + 1 au lieu de annee + 2
        {
            "start_date": datetime(annee + 1, 4, 12).date() if zone == "A" else (datetime(annee + 1, 4, 19).date() if zone == "B" else datetime(annee + 1, 4, 26).date()),
            "end_date": datetime(annee + 1, 4, 27).date() if zone == "A" else (datetime(annee + 1, 5, 4).date() if zone == "B" else datetime(annee + 1, 5, 11).date()),
            "description": f"Vacances de printemps {annee_scolaire}",
            "zone": zone
        },
        # Grandes vacances
        {
            "start_date": datetime(annee + 1, 7, 5).date(),
            "end_date": datetime(annee + 1, 8, 31).date(),
            "description": f"Grandes vacances {annee_scolaire}",
            "zone": zone
        },
    ]
    
    return [{**vac, "end_date": vac["end_date"] if "grandes vacances" in vac["description"].lower() else vac["end_date"] - timedelta(days=1)} for vac in vacances]


def get_jours_feries(annee=None):
    """
    Retourne les jours fériés français pour une année donnée.
    Calculés dynamiquement (Pâques est calculé).
    """
    from datetime import timedelta
    
    if annee is None:
        annee = datetime.now().year
    
    # Calcul de Pâques (algorithme de Butcher-Meeus)
    a = annee % 19
    b = annee // 100
    c = annee % 100
    d = b // 4
    e = b % 4
    f = (b + 8) // 25
    g = (b - f + 1) // 3
    h = (19 * a + b - d - g + 15) % 30
    i = c // 4
    k = c % 4
    l = (32 + 2 * e + 2 * i - h - k) % 7
    m = (a + 11 * h + 22 * l) // 451
    mois = (h + l - 7 * m + 114) // 31
    jour = ((h + l - 7 * m + 114) % 31) + 1
    
    paques = datetime(annee, mois, jour)
    
    # Utiliser timedelta au lieu de replace pour éviter les jours invalides
    jours_feries = [
        (datetime(annee, 1, 1), "Jour de l'an"),
        (paques, "Pâques"),
        (paques + timedelta(days=1), "Lundi de Pâques"),
        (datetime(annee, 5, 1), "Fête du travail"),
        (datetime(annee, 5, 8), "Victoire 1945"),
        (paques + timedelta(days=39), "Ascension"),
        (paques + timedelta(days=49), "Pentecôte"),
        (paques + timedelta(days=50), "Lundi de Pentecôte"),
        (datetime(annee, 7, 14), "Fête nationale"),
        (datetime(annee, 8, 15), "Assomption"),
        (datetime(annee, 11, 1), "Toussaint"),
        (datetime(annee, 11, 11), "Armistice 1918"),
        (datetime(annee, 12, 25), "Noël"),
    ]
    
    return [(d.date(), n) for d, n in jours_feries]


def import_jours_feries(annee=None, user_id=None):
    """
    Importe les jours fériés dans la base de données.
    
    Returns:
        (nombre_ajoutees, nombre_ignorees)
    """
    jours = get_jours_feries(annee)
    ajoutees = 0
    ignorees = 0
    
    for date, nom in jours:
        existing = CollegeClosure.query.filter(
            CollegeClosure.closure_type == "jour_ferie",
            CollegeClosure.start_date == date,
            CollegeClosure.end_date == date
        ).first()
        
        if existing:
            ignorees += 1
            continue
        
        closure = CollegeClosure(
            name=nom,
            start_date=date,
            end_date=date,
            closure_type="jour_ferie",
            work_hours_type="none",
            notes="Import automatique des jours fériés français",
        )
        db.session.add(closure)
        ajoutees += 1
    
    if ajoutees > 0:
        db.session.commit()
    
    return ajoutees, ignorees
