import logging
import socket
import sys
from datetime import datetime
from typing import ClassVar

from pydantic import BaseModel, Field, validator

sys.path.append(".")
# from utils.logger import ServiceLogger
import logging

from utils.client_check import ClientConfig

XCM_logger = logging.getLogger()

slide_categories = [
    "Company Overview",
    "Competitive Advantage",
    "Competitors",
    "Growth Opportunities",
    "Products and Services",
    "Sales and Marketing",
    "Clients and Customers",
    "Suppliers",
    "Operations Overview",
    "Management, Organization and Team",
    "Assets / Equipment List",
    "Industry Overview and Market",
    "Financial Information",
    "Risks",
    "Other",
]


class SlideData(BaseModel):
    """
    Contains the data for a single slide in a PowerPoint presentation.

    Attributes:
        title (str): The title of the slide.
        text (list[str]): The text on the slide.
        tables (list): The tables on the slide.
        image_path (str): The path to the image on the slide.
        is_section_divider (bool): Whether the slide is a section divider or not.
    """

    title: str = None
    text: list[str] = None
    tables: list = None
    image_path: str = None
    is_section_divider: bool = None


class SlideAnalysis(BaseModel):
    """
    Contains the analysis for a single slide in a PowerPoint presentation.

    Attributes:
        slide_categories (list[str]): The categories for the slide.
        slide_overview (str): An overview of the slide.
        slide_direction (str): The sentence structure direction for the slide.
        questions_answered_by_slide (list[str]): The questions answered by the slide.
        additional_information (list[str]): Additional questions that should be answered by the slide to make the story more engaging.
    """

    slide_categories: list[str] = Field(
        default=None,
        title=f"Pick from one of the following {slide_categories}",
    )
    slide_overview: str = Field(default=None, title="overview of the slide")
    slide_direction: str = Field(default=None, title="Sentence structure for the slide")
    questions_answered_by_slide: list[str] = Field(
        default=None, title="Questions answered by the slide"
    )
    additional_information: list[str] = Field(
        default=None,
        title="Additional questions should be answered by the slide that would help make the story more engaging",
    )


class PresentationAnalysis(BaseModel):
    """
    Contains the analysis for an entire PowerPoint presentation.

    Attributes:
        presentation_overview (str): An overview of the presentation.
        presentation_improvements (str): Improvements for the presentation.
    """

    presentation_overview: str = Field(
        default=None, title="overview of the presentation"
    )
    presentation_improvements: str = Field(
        default=None, title="improvements for the presentation"
    )


class PPTData(BaseModel):
    """
    Contains data for a PowerPoint presentation.

    Attributes:
        project_id (str): The id of the project.
        slides_data (list[SlideData]): The data for each slide.
        pptx_path (str): The path to the PowerPoint presentation.
        PPT_analysis (PresentationAnalysis): The analysis for the entire presentation.
        slides_analysis (list[SlideAnalysis]): The analysis for each slide.
        created_by (str): The username of the user who created the presentation.
        created_date (str): The date and time the presentation was created.
        modified_by (str): The username of the user who last modified the presentation.
        modified_date (str): The date and time the presentation was last modified.

    Methods:
        update_modify: Updates the modified_by and modified_date attributes.
    """

    db_table: ClassVar[str] = "presentation_analysis"

    project_id: str | None = None
    slides_data: list[SlideData] | None = None
    pptx_path: str = None
    PPT_analysis: PresentationAnalysis | None = None
    slides_analysis: list[SlideAnalysis] | None = None
    created_by: str = socket.gethostname()
    created_date: str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    modified_by: str = socket.gethostname()
    modified_date: str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    def update_modify(self):
        "Update the modified date and modified by"
        self.modified_by = socket.gethostname()
        self.modified_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    @classmethod
    def get_ppt_data(cls, project_id):
        from utils.dynamo_db import DynamoDB

        db = DynamoDB()
        table = db.dynamodb.Table(cls.db_table)
        response = db.get_item(table, project_id)
        if not response:
            return None
        return PPTData(**response)

    def is_latest_same(self):
        """
        Compare the analyzed ppt to the latest version of the ppt

        This method will check if the analyzed ppt is the same as the latest version
        of the ppt. If the analyzed ppt is the same as the latest version,
        it will return True. Otherwise, it will return False.

        If the project_id is None, it will raise a ValueError. If the presentation
        has not been analyzed yet, it will raise a RuntimeError.

        Parameters:
            None

        Returns:
            bool: True if they are the same, False if they are not
        """
        if self.project_id is None:
            raise ValueError("project_id is required")

        if self.pptx_path is None:
            raise RuntimeError("The presentation has not been analyzed yet")

        from services.ppt_generator.data_classes.project import Project
        from utils.dynamo_db import DynamoDB

        project = Project.check_project_in_db(self.project_id)
        if project.final_ppt_path != self.pptx_path:
            return False

        return True

    def save_to_db(self):
        from utils.dynamo_db import DynamoDB

        db = DynamoDB()
        self.update_modify()
        table = db.dynamodb.Table(self.db_table)
        db.upload_to_dynamodb(table, self.model_dump())


class PresentationInstructions(BaseModel):

    presentation_overview: list[str] = Field(
        default=[], title="Instructions for the presentation"
    )
    presentation_enhancements: list[str] = Field(
        default=[], title="Potential enhancements for the presentation"
    )


class SlideInstructions(BaseModel):
    slide_type: str = Field(default="Other", title="Type of slide")
    questions_to_answer: list[str] = Field(
        default=[], title="Instructions for the slide"
    )
    design_instructions: list[str] = Field(
        default=[], title="Design instructions for the slide"
    )
    slide_overview: list[str] = Field(default=[], title="Overview of the slide")

    @validator("slide_type")
    @classmethod
    def slide_type_must_be_valid(cls, value):
        "check if the slide type is valid"
        if value not in slide_categories:
            logging.info(f"Slide type {value} is not valid")
            return "Other"
            # raise ValueError(f"Slide type must be one of {slide_categories}")
        return value


class ClientTraining(BaseModel):

    db_table: ClassVar[str] = "Client_Pitch_Instructions"

    client: str = Field(
        default="XCM", title="Name of the client, which must of one of the configs"
    )

    pitch_type: str = Field(default="CIM", title="Name of the pitch type")

    presentation_instructions: PresentationInstructions = Field(
        default=PresentationInstructions(), title="Instructions for the presentation"
    )

    slides_instructions: dict[str, SlideInstructions] = Field(
        default={},
        title="Instruction for the slides. The key should be a valid slide type",
    )

    created_by: str = socket.gethostname()
    created_date: str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    modified_by: str = socket.gethostname()
    modified_date: str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    @validator("client")
    @classmethod
    def client_must_be_valid(cls, value):
        """
        Validate that the client is one of the valid clients in client mapping

        Args:
            value (str): The client to validate

        Raises:
            ValueError: If the client is not one of the valid clients

        Returns:
            str: The validated client
        """
        if value not in ClientConfig.client_mapping.keys():
            raise ValueError(
                f"Client must be one of {ClientConfig.client_mapping.keys()}"
            )
        return value

    def update_modify(self):
        "Update the modified date and modified by"
        self.modified_by = socket.gethostname()
        self.modified_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    def save_to_db(self):
        from utils.dynamo_db import DynamoDB

        db = DynamoDB()
        self.update_modify()
        table = db.dynamodb.Table(self.db_table)
        return db.upload_to_dynamodb(table, self.model_dump())
