import os
import uuid
from typing import Literal, Optional

import aiohttp
from fastapi import HTTPException
from pathvalidate import sanitize_filename
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select

from models.presentation_and_path import PresentationAndPath
from models.sql.presentation import PresentationModel
from models.sql.presentation_layout_code import PresentationLayoutCodeModel
from models.sql.slide import SlideModel
from services.database import async_session_maker
from utils.asset_directory_utils import get_exports_directory


async def export_presentation(
    presentation_id: uuid.UUID,
    title: str,
    export_as: Literal["pptx", "pdf"],
    client_id: Optional[uuid.UUID] = None,
    session: Optional[AsyncSession] = None,
) -> PresentationAndPath:
    next_url = os.environ.get("NEXT_INTERNAL_URL", "http://localhost:3000")

    if export_as == "pptx":
        # Query presentation, slides, and layout codes from the DB
        async with async_session_maker() as db:
            presentation = await db.get(PresentationModel, presentation_id)

            slides_result = await db.scalars(
                select(SlideModel)
                .where(
                    SlideModel.presentation == presentation_id,
                    SlideModel.deleted_at.is_(None),
                )
                .order_by(SlideModel.index)
            )
            slides = list(slides_result.all())

            # Fetch layout codes if the presentation uses a custom template
            template_id_str = (
                getattr(presentation, "template_name", None) if presentation else None
            )
            layouts = []
            if template_id_str:
                try:
                    template_uuid = uuid.UUID(template_id_str)
                    layouts_result = await db.scalars(
                        select(PresentationLayoutCodeModel).where(
                            PresentationLayoutCodeModel.presentation == template_uuid
                        )
                    )
                    layouts = list(layouts_result.all())
                except (ValueError, TypeError):
                    pass

        # Build JSON payload for the Next.js PptxGenJS endpoint
        payload = {
            "title": title,
            "slides": [
                {
                    "id": str(s.id),
                    "layout": s.layout,
                    "layout_group": s.layout_group,
                    "index": s.index,
                    "content": s.content or {},
                    "speaker_note": s.speaker_note,
                }
                for s in slides
            ],
            "layouts": [
                {
                    "layout_id": lay.layout_id,
                    "layout_name": lay.layout_name,
                    "layout_code": lay.layout_code,
                }
                for lay in layouts
            ],
        }

        export_directory = get_exports_directory()
        pptx_path = os.path.join(
            export_directory,
            f"{sanitize_filename(title or str(uuid.uuid4()))}.pptx",
        )

        async with aiohttp.ClientSession() as http:
            async with http.post(
                f"{next_url}/api/generate-pptx",
                json=payload,
            ) as response:
                if response.status != 200:
                    error_text = await response.text()
                    print(f"[export_utils] generate-pptx failed ({response.status}): {error_text}")
                    raise HTTPException(
                        status_code=500,
                        detail="Failed to generate PPTX",
                    )
                pptx_bytes = await response.read()

        os.makedirs(export_directory, exist_ok=True)
        with open(pptx_path, "wb") as f:
            f.write(pptx_bytes)

        return PresentationAndPath(
            presentation_id=presentation_id,
            path=pptx_path,
        )

    else:
        async with aiohttp.ClientSession() as http:
            async with http.post(
                f"{next_url}/api/export-as-pdf",
                json={
                    "id": str(presentation_id),
                    "title": sanitize_filename(title or str(uuid.uuid4())),
                },
            ) as response:
                response_json = await response.json()

        return PresentationAndPath(
            presentation_id=presentation_id,
            path=response_json["path"],
        )
