import json
from typing import List
import uuid, aiohttp
from fastapi import HTTPException
from api.models import LogMetadata
from api.routers.presentation.handlers.export_as_pptx import ExportAsPptxHandler
from api.routers.presentation.handlers.upload_files import UploadFilesHandler
from api.routers.presentation.mixins.fetch_assets_on_generation import (
    FetchAssetsOnPresentationGenerationMixin,
)
from api.routers.presentation.models import (
    ExportAsRequest,
    GeneratePresentationRequest,
    PresentationAndPath,
    PresentationPathAndEditPath,
)
from api.services.database import get_sql_session
from api.services.instances import TEMP_FILE_SERVICE
from api.services.logging import LoggingService
from api.sql_models import PresentationSqlModel, SlideSqlModel
from api.utils.utils import get_presentation_dir
from api.utils.model_utils import is_custom_llm_selected, is_ollama_selected
from document_processor.loader import DocumentsLoader
from ppt_config_generator.document_summary_generator import generate_document_summary
from ppt_config_generator.models import PresentationMarkdownModel
from ppt_config_generator.ppt_outlines_generator import generate_ppt_content
from ppt_generator.generator import generate_presentation
from ppt_generator.models.llm_models import (
    LLM_CONTENT_TYPE_MAPPING,
)
from ppt_generator.models.slide_model import SlideModel


class GeneratePresentationHandler(FetchAssetsOnPresentationGenerationMixin):

    def __init__(self, presentation_id: str, data: GeneratePresentationRequest):
        self.session = str(uuid.uuid4())
        self.presentation_id = presentation_id
        self.data = data

        self.temp_dir = TEMP_FILE_SERVICE.create_temp_dir()
        self.presentation_dir = get_presentation_dir(self.presentation_id)

    def __del__(self):
        TEMP_FILE_SERVICE.cleanup_temp_dir(self.temp_dir)

    async def post(self, logging_service: LoggingService, log_metadata: LogMetadata):
        if is_ollama_selected() or is_custom_llm_selected():
            raise HTTPException(
                status_code=400,
                detail="Ollama is not currently supported for this endpoint",
            )

        documents_and_images_path = await UploadFilesHandler(
            documents=self.data.documents,
            images=None,
        ).post(logging_service, log_metadata)

        summary = None
        if documents_and_images_path.documents:
            documents_loader = DocumentsLoader(documents_and_images_path.documents)
            await documents_loader.load_documents(self.temp_dir)

            print("-" * 40)
            print("Generating Document Summary")
            summary = await generate_document_summary(documents_loader.documents)

        print("-" * 40)
        print("Generating PPT Outline")
        presentation_content = await generate_ppt_content(
            self.data.prompt,
            self.data.n_slides,
            self.data.language,
            summary,
        )

        print("-" * 40)
        print("Generating Presentation")
        presentation_text = await generate_presentation(
            PresentationMarkdownModel(
                title=presentation_content.title,
                slides=presentation_content.slides,
                notes=presentation_content.notes,
            )
        )

        print("-" * 40)
        print("Parsing Presentation")
        presentation_json = json.loads(presentation_text)

        slide_models: List[SlideModel] = []
        for i, slide in enumerate(presentation_json["slides"]):
            slide["index"] = i
            slide["presentation"] = self.presentation_id
            slide["content"] = (
                LLM_CONTENT_TYPE_MAPPING[slide["type"]](**slide["content"])
                .to_content()
                .model_dump(mode="json")
            )
            slide_model = SlideModel(**slide)
            slide_models.append(slide_model)

        print("-" * 40)
        print("Fetching Theme Colors")
        async with aiohttp.ClientSession() as session:
            async with session.get(
                f"http://localhost/api/get-theme-from-name?theme={self.data.theme.value}",
            ) as response:
                self.theme = await response.json()

        print("-" * 40)
        print("Fetching Slide Assets")
        async for result in self.fetch_slide_assets(slide_models):
            print(result)

        slide_sql_models = [
            SlideSqlModel(**each.model_dump(mode="json")) for each in slide_models
        ]

        presentation = PresentationSqlModel(
            id=self.presentation_id,
            prompt=self.data.prompt,
            n_slides=self.data.n_slides,
            language=self.data.language,
            summary=summary,
            theme=self.theme,
            title=presentation_content.title,
            outlines=[each.model_dump() for each in presentation_content.slides],
            notes=presentation_content.notes,
        )

        with get_sql_session() as sql_session:
            sql_session.add(presentation)
            sql_session.add_all(slide_sql_models)
            sql_session.commit()
            for each in slide_sql_models:
                sql_session.refresh(each)

        if self.data.export_as == "pptx":
            print("-" * 40)
            print("Fetching Slide Metadata for Export")
            async with aiohttp.ClientSession() as session:
                async with session.post(
                    f"http://localhost/api/slide-metadata",
                    json={
                        "url": f"http://localhost/presentation?id={self.presentation_id}",
                        "theme": self.theme["name"],
                        "customColors": self.theme["colors"],
                    },
                ) as response:
                    export_request_body = await response.json()

            print("-" * 40)
            print("Exporting Presentation")
            export_request_body["presentation_id"] = self.presentation_id
            export_request = ExportAsRequest(**export_request_body)

            presentation_and_path = await ExportAsPptxHandler(export_request).post(
                logging_service, log_metadata
            )

        else:
            print("-" * 40)
            print("Exporting Presentation as PDF")

            async with aiohttp.ClientSession() as session:
                async with session.post(
                    f"http://localhost/api/export-as-pdf",
                    json={
                        "url": f"http://localhost/pdf-maker?id={self.presentation_id}",
                        "title": presentation_content.title,
                    },
                ) as response:
                    response_json = await response.json()

            presentation_and_path = PresentationAndPath(
                presentation_id=self.presentation_id,
                path=response_json["path"].replace("app", "static"),
            )

        presentation_and_path.path = presentation_and_path.path.replace("app", "static")
        return PresentationPathAndEditPath(
            **presentation_and_path.model_dump(),
            edit_path=f"/presentation?id={self.presentation_id}",
        )
