import base64
import logging
import os
from datetime import datetime, timezone

import requests
import streamlit as st
from dateutil import parser

from config import DEPOT_CODE, DEPOT_FICHES, DOT_FILE, ENV, ENV_CODE, GITEA_TOKEN, GITEA_URL, ORGANISATION


def lire_fichier_local(nom_fichier):
    """Lit le contenu d'un fichier local en UTF-8.

    Args:
        nom_fichier: Chemin vers le fichier a lire.

    Returns:
        str: Contenu du fichier.
    """
    with open(nom_fichier, encoding="utf-8") as f:
        contenu_md = f.read()
    return contenu_md

def charger_instructions_depuis_gitea(nom_fichier="Instructions.md"):
    """Charge le fichier Instructions.md depuis Gitea avec cache local timestamp.

    Telecharge le fichier depuis Gitea uniquement si la version distante est plus
    recente que la version locale. Utilise le cache local en priorite.

    Args:
        nom_fichier: Nom du fichier a charger. Defaut: "Instructions.md".

    Returns:
        str | None: Contenu du fichier en markdown, ou None si erreur sans cache.
    """
    headers = {"Authorization": f"token {GITEA_TOKEN}"}
    url = f"{GITEA_URL}/repos/{ORGANISATION}/{DEPOT_FICHES}/contents/{nom_fichier}?ref={ENV}"
    try:
        # Vérifier si une version plus récente existe sur le dépôt
        remote_last_modified = recuperer_date_dernier_commit(f"{GITEA_URL}/repos/{ORGANISATION}/{DEPOT_FICHES}/commits?path={nom_fichier}&sha={ENV}")
        local_last_modified = datetime.fromtimestamp(os.path.getmtime(nom_fichier), tz=timezone.utc) if os.path.exists(nom_fichier) else None

        # Si le fichier local n'existe pas ou si la version distante est plus récente
        if not local_last_modified or (remote_last_modified and remote_last_modified > local_last_modified):
            response = requests.get(url, headers=headers)
            response.raise_for_status()
            data = response.json()
            contenu_md = base64.b64decode(data["content"]).decode("utf-8")
            # Sauvegarder en local
            with open(nom_fichier, "w", encoding="utf-8") as f:
                f.write(contenu_md)
            return contenu_md
        # Lire depuis le cache local
        return lire_fichier_local(nom_fichier)
    except Exception as e:
        st.error(f"Erreur chargement instructions Gitea : {e}")
        # Essayer de charger depuis le cache local en cas d'erreur
        if os.path.exists(nom_fichier):
            return lire_fichier_local(nom_fichier)
        return None


def recuperer_date_dernier_commit(url):
    """Recupere la date du dernier commit pour un fichier via l'API Gitea.

    Args:
        url: URL de l'API Gitea pour les commits (format: /repos/.../commits?path=...&sha=...).

    Returns:
        datetime | None: Date du dernier commit en timezone-aware, ou None si erreur.
    """
    headers = {"Authorization": f"token {GITEA_TOKEN}"}
    try:
        response = requests.get(url, headers=headers, timeout=10)
        response.raise_for_status()
        commits = response.json()
        if commits:
            return parser.isoparse(commits[0]["commit"]["author"]["date"])
    except Exception as e:
        logging.error(f"Erreur récupération commit schema : {e}")
    return None


def charger_schema_depuis_gitea(fichier_local="schema_temp.txt"):
    """Charge le schema DOT depuis Gitea avec cache local base sur timestamp.

    Telecharge le fichier schema DOT depuis le depot Gitea CODE uniquement si
    la version distante est plus recente que la version locale (ou si aucune
    version locale n'existe).

    Args:
        fichier_local: Chemin du fichier cache local. Defaut: "schema_temp.txt".

    Returns:
        str | None: "OK" si succes, None si erreur.
    """
    headers = {"Authorization": f"token {GITEA_TOKEN}"}
    url = f"{GITEA_URL}/repos/{ORGANISATION}/{DEPOT_CODE}/contents/{DOT_FILE}?ref={ENV_CODE}"
    try:
        response = requests.get(url, headers=headers, timeout=10)
        response.raise_for_status()
        data = response.json()

        remote_last_modified = recuperer_date_dernier_commit(f"{GITEA_URL}/repos/{ORGANISATION}/{DEPOT_CODE}/commits?path={DOT_FILE}&sha={ENV_CODE}")
        local_last_modified = datetime.fromtimestamp(os.path.getmtime(fichier_local), tz=timezone.utc) if os.path.exists(fichier_local) else None

        if not local_last_modified or (remote_last_modified and remote_last_modified > local_last_modified):
            dot_text = base64.b64decode(data["content"]).decode("utf-8")
            with open(fichier_local, "w", encoding="utf-8") as f:
                f.write(dot_text)

        return "OK"
    except Exception as e:
        logging.error(f"Erreur chargement schema Gitea : {e}")
        return None


def charger_arborescence_fiches():
    """Charge l'arborescence complete des fiches depuis le depot Gitea.

    Recupere la liste des dossiers et fichiers .md dans le repertoire Documents
    du depot DEPOT_FICHES. Les resultats sont tries par ordre alphabetique.

    Returns:
        dict: Arborescence au format {nom_dossier: [{"nom": str, "download_url": str}, ...]}.
              Retourne un dict vide en cas d'erreur.
    """
    headers = {"Authorization": f"token {GITEA_TOKEN}"}
    url_base = f"{GITEA_URL}/repos/{ORGANISATION}/{DEPOT_FICHES}/contents/Documents?ref={ENV}"

    try:
        response = requests.get(url_base, headers=headers)
        response.raise_for_status()
        dossiers = response.json()
        arbo = {}

        for dossier in sorted(dossiers, key=lambda d: d['name'].lower()):
            if dossier['type'] == 'dir':
                dossier_name = dossier['name']
                url_dossier = dossier['url']
                response_dossier = requests.get(url_dossier, headers=headers)
                response_dossier.raise_for_status()
                fichiers = response_dossier.json()
                fiches = sorted(
                    [
                        {"nom": f["name"], "download_url": f["download_url"]}
                        for f in fichiers if f["name"].endswith(".md")
                    ],
                    key=lambda x: x['nom'].lower()
                )
                arbo[dossier_name] = fiches

        return arbo
    except Exception as e:
        logging.error(f"Erreur chargement fiches : {e}")
        return {}
