import uuid
from datetime import datetime, timedelta, timezone

from fastapi import HTTPException
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession

from app.models.invitation import Invitation
from app.models.utilisateur import Utilisateur


class InvitationService:
    def __init__(self, db: AsyncSession) -> None:
        self.db = db

    async def creer_invitation(
        self, email: str, type_utilisateur: str, current_user: Utilisateur
    ) -> dict:
        """Create a new invitation for a user."""
        normalized_role = (type_utilisateur or "UTILISATEUR").upper()
        if normalized_role == "SUPERVISEUR":
            normalized_role = "ADMIN_SYSTEME"
        if normalized_role == "MODERATEUR":
            normalized_role = "GESTIONNAIRE"

        allowed_roles = {"UTILISATEUR", "GESTIONNAIRE", "ADMIN_SYSTEME"}
        if normalized_role not in allowed_roles:
            raise HTTPException(status_code=400, detail="Rôle utilisateur invalide")

        # Check if email already exists as a user
        existing_user = (
            await self.db.execute(
                select(Utilisateur).where(Utilisateur.email == email)
            )
        ).scalar_one_or_none()
        
        if existing_user:
            raise HTTPException(status_code=409, detail="Email déjà utilisé")
        
        # Check if invitation already pending
        existing_inv = (
            await self.db.execute(
                select(Invitation).where(
                    Invitation.email == email,
                    Invitation.statut == "PENDING",
                )
            )
        ).scalar_one_or_none()
        
        if existing_inv:
            raise HTTPException(status_code=409, detail="Invitation déjà envoyée")
        
        # Create invitation (valid for 7 days)
        expiration = datetime.now(timezone.utc) + timedelta(days=7)
        invitation = Invitation(
            email=email,
            type_utilisateur=normalized_role,
            statut="PENDING",
            invite_par_id=current_user.id,
            date_expiration=expiration,
        )
        self.db.add(invitation)
        await self.db.commit()
        await self.db.refresh(invitation)
        
        return self._serialize(invitation)

    async def list_invitations(
        self,
        page: int = 0,
        size: int = 20,
        statut: str | None = None,
    ) -> tuple[list[dict], int]:
        q = select(Invitation)
        if statut:
            q = q.where(Invitation.statut == statut.upper())

        total = (await self.db.execute(select(func.count()).select_from(q.subquery()))).scalar_one()
        rows = (
            await self.db.execute(
                q.order_by(Invitation.date_creation.desc()).offset(page * size).limit(size)
            )
        ).scalars().all()
        return [self._serialize(item) for item in rows], total

    def _serialize(self, invitation: Invitation) -> dict:
        return {
            "invitationId": str(invitation.id),
            "email": invitation.email,
            "typeUtilisateur": invitation.type_utilisateur,
            "statut": invitation.statut,
            "expireLe": invitation.date_expiration,
            "dateCreation": invitation.date_creation,
        }
