import uuid
import logging
from datetime import datetime, timezone, timedelta
from sqlalchemy import select, func, desc
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload

from app.models.rapport import Rapport
from app.models.utilisateur import Utilisateur
from app.services.fichier_service import FichierService

logger = logging.getLogger(__name__)


class ExportService:
    def __init__(self, db: AsyncSession) -> None:
        self.db = db

    async def list_reports(self, page: int = 1, size: int = 20, type_filter: str | None = None, status_filter: str | None = None) -> tuple[list[Rapport], int]:
        # Build base filters
        filters = []
        if type_filter:
            filters.append(Rapport.type == type_filter.upper())
        if status_filter:
            db_status = self._map_ui_status_to_db(status_filter)
            filters.append(Rapport.statut == db_status)
        
        # count query
        count_stmt = select(func.count()).select_from(Rapport)
        if filters:
            count_stmt = count_stmt.where(*filters)
        total = (await self.db.execute(count_stmt)).scalar_one()
        
        # data query with eager loading
        stmt = select(Rapport).options(selectinload(Rapport.genere_par))
        if filters:
            stmt = stmt.where(*filters)
        stmt = stmt.order_by(desc(Rapport.date_creation))
        
        # pagination
        offset = (page - 1) * size
        stmt = stmt.offset(offset).limit(size)
        result = await self.db.execute(stmt)
        items = result.scalars().all()
        return list(items), total

    async def get_report_by_id(self, report_id: str) -> Rapport | None:
        try:
            report_uuid = uuid.UUID(report_id)
        except ValueError:
            return None
        result = await self.db.execute(
            select(Rapport)
            .options(selectinload(Rapport.genere_par))
            .where(Rapport.id == report_uuid)
        )
        return result.scalar_one_or_none()

    async def create_report(self, title: str, report_type: str, export_format: str, description: str | None = None, period_start: datetime | None = None, period_end: datetime | None = None, user_id: str | None = None, is_scheduled: bool = False, schedule_config: dict | None = None) -> Rapport:
        user_uuid = uuid.UUID(user_id) if user_id else None
        
        parametres = {
            "format": export_format,
            "periodStart": period_start.isoformat() if period_start else None,
            "periodEnd": period_end.isoformat() if period_end else None,
        }
        
        db_type = report_type.upper()
        
        rapport = Rapport(
            titre=title,
            type=db_type,
            statut="EN_COURS",
            genere_par_id=user_uuid,
            parametres=parametres,
            description=description,
        )
        if is_scheduled and schedule_config:
            rapport.parametres["scheduleConfig"] = schedule_config
            rapport.statut = "EN_ATTENTE" # scheduled report starts in EN_ATTENTE (draft)
            
        self.db.add(rapport)
        await self.db.commit()
        await self.db.refresh(rapport)
        
        if not is_scheduled:
            # Trigger generation instantly
            await self.generate_report_file(str(rapport.id))
            
        return rapport

    async def generate_report_file(self, report_id: str) -> Rapport | None:
        rapport = await self.get_report_by_id(report_id)
        if not rapport:
            return None
            
        rapport.statut = "EN_COURS"
        await self.db.commit()
        
        try:
            fmt = (rapport.parametres or {}).get("format", "pdf").lower()
            filename = f"{rapport.titre.lower().replace(' ', '_')}_{report_id[:8]}.{fmt}"
            
            if fmt == "csv":
                content = b"Date;Titre;Type;Statut;Description\n2026-06-27;Mock report;VBG;NOUVEAU;Mock CSV detail"
                content_type = "text/csv"
            elif fmt in ("xlsx", "excel"):
                content = b"Mock Excel binary content for test"
                content_type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
            else: # pdf
                content = b"%PDF-1.4 ... (Mock report content for Campus Safe)"
                content_type = "application/pdf"
                
            fs = FichierService()
            upload_result = await fs.upload(filename, content, content_type)
            
            rapport.url_fichier = upload_result["url"]
            rapport.resultats = {
                "fileId": upload_result["fileId"],
                "taille": upload_result["taille"],
                "nom": upload_result["nom"],
            }
            rapport.statut = "TERMINE"
            rapport.date_generation = datetime.now(timezone.utc)
            
        except Exception as e:
            logger.error("Error generating report file: %s", e)
            rapport.statut = "ERREUR"
            rapport.description = f"Erreur de generation: {str(e)}"
            
        await self.db.commit()
        await self.db.refresh(rapport)
        return rapport

    async def delete_report(self, report_id: str) -> bool:
        rapport = await self.get_report_by_id(report_id)
        if not rapport:
            return False
            
        if rapport.resultats and "fileId" in rapport.resultats:
            try:
                fs = FichierService()
                await fs.delete(rapport.resultats["fileId"])
            except Exception as e:
                logger.error("Error deleting physical report file: %s", e)
                
        await self.db.delete(rapport)
        await self.db.commit()
        return True

    async def archive_report(self, report_id: str) -> Rapport | None:
        rapport = await self.get_report_by_id(report_id)
        if not rapport:
            return None
        rapport.statut = "ARCHIVE"
        await self.db.commit()
        await self.db.refresh(rapport)
        return rapport

    def _map_ui_status_to_db(self, ui_status: str) -> str:
        mapping = {
            "draft": "EN_ATTENTE",
            "generating": "EN_COURS",
            "ready": "TERMINE",
            "failed": "ERREUR",
            "archived": "ARCHIVE"
        }
        return mapping.get(ui_status.lower(), "TERMINE")

    async def create_signalements_export(
        self,
        format: str = "csv",
        date_debut: datetime | None = None,
        date_fin: datetime | None = None,
        statuts: list[str] | None = None,
        current_user: Utilisateur | None = None,
    ) -> dict:
        rapport = await self.create_report(
            title=f"Export Signalements {format.upper()}",
            report_type="incidents",
            export_format=format,
            description=f"Export au format {format}",
            period_start=date_debut,
            period_end=date_fin,
            user_id=str(current_user.id) if current_user else None,
        )
        return {
            "exportId": str(rapport.id),
            "exportedAt": rapport.date_creation,
            "downloadUrl": rapport.url_fichier,
            "format": format,
        }
