"""
Authentification MAESTRO
"""
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from pydantic import BaseModel
import hashlib
import jwt
from datetime import datetime, timedelta

from app.database import get_db
from app.models.utilisateur import Utilisateur

router = APIRouter(prefix="/api/auth", tags=["auth"])

SECRET_KEY = "maestro_secret_key_2026"
ALGORITHM = "HS256"
TOKEN_EXPIRE_HOURS = 24


def hash_mdp(mdp: str) -> str:
    return hashlib.sha256(mdp.encode()).hexdigest()


def creer_token(utilisateur_id: int, nom: str, role: str) -> str:
    expire = datetime.utcnow() + timedelta(hours=TOKEN_EXPIRE_HOURS)
    payload = {
        "sub": utilisateur_id,
        "nom": nom,
        "role": role,
        "exp": expire
    }
    return jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM)


def verifier_token(token: str) -> dict:
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        return payload
    except jwt.ExpiredSignatureError:
        raise HTTPException(401, "Token expiré")
    except jwt.InvalidTokenError:
        raise HTTPException(401, "Token invalide")


class LoginRequest(BaseModel):
    email: str
    mot_de_passe: str


class UtilisateurCreate(BaseModel):
    nom: str
    email: str
    mot_de_passe: str
    role: str = "utilisateur"


@router.post("/login")
def login(data: LoginRequest, db: Session = Depends(get_db)):
    user = db.query(Utilisateur).filter(
        Utilisateur.email == data.email,
        Utilisateur.actif == 1
    ).first()

    if not user or user.mot_de_passe != hash_mdp(data.mot_de_passe):
        raise HTTPException(401, "Email ou mot de passe incorrect")

    token = creer_token(user.id, user.nom, user.role)
    return {
        "token": token,
        "utilisateur": {
            "id": user.id,
            "nom": user.nom,
            "email": user.email,
            "role": user.role
        }
    }


@router.get("/me")
def get_me(token: str, db: Session = Depends(get_db)):
    payload = verifier_token(token)
    user = db.query(Utilisateur).filter(Utilisateur.id == payload["sub"]).first()
    if not user:
        raise HTTPException(404, "Utilisateur introuvable")
    return {
        "id": user.id,
        "nom": user.nom,
        "email": user.email,
        "role": user.role
    }


@router.post("/utilisateurs")
def creer_utilisateur(data: UtilisateurCreate, db: Session = Depends(get_db)):
    existing = db.query(Utilisateur).filter(Utilisateur.email == data.email).first()
    if existing:
        raise HTTPException(400, "Email déjà utilisé")

    user = Utilisateur(
        nom=data.nom,
        email=data.email,
        mot_de_passe=hash_mdp(data.mot_de_passe),
        role=data.role
    )
    db.add(user)
    db.commit()
    db.refresh(user)
    return {"id": user.id, "nom": user.nom, "email": user.email, "role": user.role}


@router.get("/utilisateurs")
def liste_utilisateurs(db: Session = Depends(get_db)):
    users = db.query(Utilisateur).filter(Utilisateur.actif == 1).all()
    return [{"id": u.id, "nom": u.nom, "email": u.email, "role": u.role} for u in users]


@router.put("/utilisateurs/{user_id}")
def modifier_utilisateur(user_id: int, data: UtilisateurCreate, db: Session = Depends(get_db)):
    user = db.query(Utilisateur).filter(Utilisateur.id == user_id).first()
    if not user:
        raise HTTPException(404, "Utilisateur introuvable")
    user.nom = data.nom
    user.email = data.email
    if data.mot_de_passe and data.mot_de_passe != 'UNCHANGED':
        user.mot_de_passe = hash_mdp(data.mot_de_passe)
    user.role = data.role
    db.commit()
    return {"ok": True}


@router.delete("/utilisateurs/{user_id}")
def supprimer_utilisateur(user_id: int, db: Session = Depends(get_db)):
    user = db.query(Utilisateur).filter(Utilisateur.id == user_id).first()
    if not user:
        raise HTTPException(404, "Utilisateur introuvable")
    user.actif = 0
    db.commit()
    return {"ok": True}