import re
import secrets
from pathlib import Path

from fastapi import APIRouter, Depends, Form, HTTPException, Request
from fastapi.responses import FileResponse, RedirectResponse
from fastapi.templating import Jinja2Templates
from sqlalchemy.orm import Session

from app.config import (
    definir_dossier_sauvegarde,
    definir_identifiants_google,
    detecter_dossiers_cloud,
    obtenir_dossier_sauvegarde,
    obtenir_identifiants_google,
    supprimer_jeton_google,
)
from app.database import get_db
from app.google_drive import ErreurGoogleDrive, compte_connecte, connecter_compte, construire_url_autorisation
from app.sauvegarde import NOM_PREFIXE, creer_sauvegarde, lister_sauvegardes
from app.securite import exiger_admin, obtenir_jeton_csrf, verifier_csrf

router = APIRouter(prefix="/parametres", tags=["parametres"], dependencies=[Depends(exiger_admin)])
templates = Jinja2Templates(directory="app/templates")

NOM_FICHIER_VALIDE = re.compile(rf"^{re.escape(NOM_PREFIXE)}\d{{4}}-\d{{2}}-\d{{2}}_\d{{6}}\.zip$")
REDIRECT_URI_GOOGLE = "http://127.0.0.1:8000/parametres/google/callback"


@router.get("")
def page_parametres(request: Request, db: Session = Depends(get_db)):
    sauvegardes = [
        {"nom": p.name, "taille_ko": round(p.stat().st_size / 1024, 1)} for p in lister_sauvegardes()
    ]
    client_id, client_secret = obtenir_identifiants_google()
    return templates.TemplateResponse(
        "parametres.html",
        {
            "request": request,
            "sauvegardes": sauvegardes,
            "dossier_sauvegarde": str(obtenir_dossier_sauvegarde()),
            "comptes_cloud_detectes": detecter_dossiers_cloud(),
            "google_identifiants_configures": bool(client_id and client_secret),
            "google_client_id": client_id or "",
            "google_compte_connecte": compte_connecte(),
            "csrf_token": obtenir_jeton_csrf(request),
        },
    )


@router.post("/sauvegarder")
def declencher_sauvegarde(request: Request, csrf_token: str = Form(...)):
    if not verifier_csrf(request, csrf_token):
        raise HTTPException(status_code=403, detail="Jeton de sécurité invalide")
    _, erreur_drive = creer_sauvegarde()
    if erreur_drive:
        return RedirectResponse(
            url=f"/parametres?erreur=Sauvegarde locale créée, mais échec de l'envoi vers Google Drive : {erreur_drive}",
            status_code=303,
        )
    return RedirectResponse(url="/parametres?succes=Sauvegarde créée", status_code=303)


@router.post("/dossier")
def modifier_dossier_sauvegarde(request: Request, csrf_token: str = Form(...), dossier_sauvegarde: str = Form(...)):
    if not verifier_csrf(request, csrf_token):
        raise HTTPException(status_code=403, detail="Jeton de sécurité invalide")

    dossier = dossier_sauvegarde.strip()
    if not dossier or not Path(dossier).is_absolute():
        return RedirectResponse(
            url="/parametres?erreur=Chemin de dossier invalide (indiquez un chemin complet, ex. D:\\Mon Drive\\ELFIRMA)",
            status_code=303,
        )

    try:
        Path(dossier).mkdir(parents=True, exist_ok=True)
    except OSError:
        return RedirectResponse(
            url="/parametres?erreur=Impossible de créer ce dossier, vérifiez le chemin", status_code=303
        )

    definir_dossier_sauvegarde(dossier)
    return RedirectResponse(url="/parametres?succes=Dossier de sauvegarde mis à jour", status_code=303)


@router.post("/google/identifiants")
def enregistrer_identifiants_google(
    request: Request,
    csrf_token: str = Form(...),
    google_client_id: str = Form(...),
    google_client_secret: str = Form(...),
):
    if not verifier_csrf(request, csrf_token):
        raise HTTPException(status_code=403, detail="Jeton de sécurité invalide")

    client_id = google_client_id.strip()
    client_secret = google_client_secret.strip()
    if not client_id.endswith(".apps.googleusercontent.com"):
        return RedirectResponse(
            url=(
                "/parametres?erreur=Ceci ne ressemble pas à un Client ID Google valide "
                "(il doit se terminer par .apps.googleusercontent.com). Ce n'est ni votre identifiant "
                "ELFIRMA, ni votre email ou mot de passe Google : voir les instructions ci-dessus."
            ),
            status_code=303,
        )
    if len(client_secret) < 10:
        return RedirectResponse(
            url="/parametres?erreur=Ce Client Secret semble incorrect, vérifiez la valeur copiée depuis Google Cloud Console",
            status_code=303,
        )

    definir_identifiants_google(client_id, client_secret)
    return RedirectResponse(url="/parametres?succes=Identifiants Google enregistrés", status_code=303)


@router.get("/google/connecter")
def connecter_google(request: Request):
    state = secrets.token_hex(16)
    request.session["google_oauth_state"] = state
    try:
        url = construire_url_autorisation(REDIRECT_URI_GOOGLE, state)
    except ErreurGoogleDrive as exc:
        return RedirectResponse(url=f"/parametres?erreur={exc}", status_code=303)
    return RedirectResponse(url=url, status_code=303)


@router.get("/google/callback")
def callback_google(request: Request, code: str | None = None, state: str | None = None, error: str | None = None):
    state_attendu = request.session.pop("google_oauth_state", None)
    if error:
        return RedirectResponse(url=f"/parametres?erreur=Connexion Google refusée ({error})", status_code=303)
    if not state or not state_attendu or not secrets.compare_digest(state, state_attendu):
        raise HTTPException(status_code=403, detail="Requête de connexion Google invalide ou expirée")
    if not code:
        return RedirectResponse(url="/parametres?erreur=Code Google manquant", status_code=303)

    try:
        email = connecter_compte(code, REDIRECT_URI_GOOGLE)
    except ErreurGoogleDrive as exc:
        return RedirectResponse(url=f"/parametres?erreur={exc}", status_code=303)

    return RedirectResponse(url=f"/parametres?succes=Compte Google connecté ({email})", status_code=303)


@router.post("/google/deconnecter")
def deconnecter_google(request: Request, csrf_token: str = Form(...)):
    if not verifier_csrf(request, csrf_token):
        raise HTTPException(status_code=403, detail="Jeton de sécurité invalide")
    supprimer_jeton_google()
    return RedirectResponse(url="/parametres?succes=Compte Google déconnecté", status_code=303)


@router.get("/sauvegardes/{nom_fichier}")
def telecharger_sauvegarde(nom_fichier: str):
    if not NOM_FICHIER_VALIDE.match(nom_fichier):
        raise HTTPException(status_code=404, detail="Sauvegarde introuvable")

    dossier = obtenir_dossier_sauvegarde().resolve()
    chemin = (dossier / nom_fichier).resolve()
    if chemin.parent != dossier or not chemin.is_file():
        raise HTTPException(status_code=404, detail="Sauvegarde introuvable")

    return FileResponse(chemin, filename=nom_fichier, media_type="application/zip")
