from fastapi import HTTPException
from pydantic_core import ValidationError
from pymongo.database import Database
from pymongo.results import UpdateResult
from starlette import status
from typing import get_type_hints

from Schemas.models.model import Model
from Schemas.models.objectid import PydanticObjectId
from Schemas.models.schools.ExamResullt import ExamResult
from Schemas.models.schools.FinancialData import FinancialData
from Schemas.models.schools.GeneralInfo import GeneralInfo
from Schemas.models.schools.IdAndLocation import IdAndLocation
from Schemas.models.schools.OfficeAndFurniture import OfficeAndFurniture
from Schemas.models.schools.ParticipatorySchoolManagement import ParticipatorySchoolManagement
from Schemas.models.schools.SocioEnvironnement import SocioEnvironnement
from Schemas.models.schools.StudentsRecord import StudentsRecord
from Schemas.models.schools.TeachingAndLearningEquipment import TeachingAndLearningEquipment
from Schemas.models.schools.TeachingStaff import TeachingStaff


class Schools(Model):
    name: str
    id_and_location: IdAndLocation
    socio_environnement: SocioEnvironnement
    general_info: GeneralInfo
    office_and_furniture: OfficeAndFurniture
    teaching_and_learning_equipment: TeachingAndLearningEquipment
    teaching_staff: TeachingStaff
    exam_results: ExamResult
    participatory_school_management: ParticipatorySchoolManagement
    financial_data: FinancialData
    students_record: StudentsRecord

    @classmethod
    def find_one(cls, database: Database, mask: dict):
        if result := database.Schools.find_one(mask):
            # Exclude _id from the result

            return Schools(**result)
        else:
            return None

    @classmethod
    def find_one_or_404(cls, database: Database, mask: dict):
        if result := database.Schools.find_one(mask):
            # Exclude _id from the result

            return Schools(**result)
        else:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="Utilisateur non trouvé",
            )

    def save(self):
        data = self.to_bson()
        result = self.database.Schools.insert_one(data)
        self.id = PydanticObjectId(result.inserted_id)

    def full_update(self, data: dict):
        self.database.Schools.update_one({"_id": self.id},
                                         {"$set": data})
        self.__init__(**Schools.find_one_or_404(self.database, {"_id": self.id}).dict())

    def partial_update(self, data: dict, section: str) -> UpdateResult:
        try:
            section_model = get_type_hints(Schools)
            validator = section_model[section]
            validator(**data)
            result = self.database.Schools.update_one({"_id": self.id},
                                                      {"$set": {section: data}})
            self.__init__(**Schools.find_one_or_404(self.database, {"_id": self.id}).dict())
            return result
        except ValidationError as e:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=e.errors()
            )

