from template_project.application.common.data_structure import to_data_structure
from template_project.application.common.enums import EducationGrade, ExperienceType
from template_project.application.common.identity_provider import IdentityProvider
from template_project.application.common.interactor import to_interactor
from template_project.application.common.unit_of_work import UnitOfWork
from template_project.application.resume.data_gateway import (
    ResumeDataGateway,
    ResumeEducationDataGateway,
    ResumeExperienceDataGateway,
    ResumeProjectDataGateway,
)
from template_project.application.resume.entity import (
    Resume,
    ResumeEducation,
    ResumeExperience,
    ResumeId,
    ResumeProject,
)
from template_project.application.resume.errors import ResumeDoesBelongUserError, ResumeNotFoundError


@to_data_structure
class ExperienceInput:
    place: str
    description: str
    months_duration: int


@to_data_structure
class EducationInput:
    place: str
    grade: EducationGrade
    specialization: str
    description: str | None = None


@to_data_structure
class ProjectInput:
    name: str
    description: str


@to_data_structure
class ExperienceItemResponse:
    place: str
    description: str
    months_duration: int


@to_data_structure
class EducationItemResponse:
    place: str
    grade: EducationGrade
    specialization: str
    description: str | None


@to_data_structure
class ProjectItemResponse:
    name: str
    description: str


@to_data_structure
class EditResumeResponse:
    id: ResumeId
    position: str
    location: str
    about_me: str
    key_skills: list[str]
    experience_type: ExperienceType
    experience: list[ExperienceItemResponse]
    education: list[EducationItemResponse]
    projects: list[ProjectItemResponse]


@to_interactor
class EditResumeInteractor:
    unit_of_work: UnitOfWork
    identity_provider: IdentityProvider
    resume_data_gateway: ResumeDataGateway
    resume_experience_data_gateway: ResumeExperienceDataGateway
    resume_education_data_gateway: ResumeEducationDataGateway
    resume_project_data_gateway: ResumeProjectDataGateway

    async def execute(
        self,
        resume_id: ResumeId,
        position: str | None,
        location: str | None,
        about_me: str | None,
        key_skills: list[str] | None,
        experience_type: ExperienceType | None,
        experience: list[ExperienceInput] | None = None,
        education: list[EducationInput] | None = None,
        projects: list[ProjectInput] | None = None,
    ) -> EditResumeResponse:
        user = await self.identity_provider.get_current_user()
        old_resume = await self.resume_data_gateway.load_by_resume_id(resume_id)
        if old_resume is None:
            raise ResumeNotFoundError(resume_id=resume_id)
        if old_resume.user_id != user.id:
            raise ResumeDoesBelongUserError

        new_position = position if position is not None else old_resume.position
        new_location = location if location is not None else old_resume.location
        new_about_me = about_me if about_me is not None else old_resume.about_me
        new_key_skills = key_skills if key_skills is not None else old_resume.key_skills
        new_experience_type = experience_type if experience_type is not None else old_resume.experience_type

        new_resume = Resume.factory(
            user_id=user.id,
            position=new_position,
            location=new_location,
            about_me=new_about_me,
            key_skills=new_key_skills,
            experience_type=new_experience_type,
            down_resume_id=old_resume.id,
            up_resume_id=None,
        )

        await self.unit_of_work.add(new_resume)

        if experience is not None:
            for exp in experience:
                resume_experience = ResumeExperience.factory(
                    resume_id=new_resume.id,
                    place=exp.place,
                    description=exp.description,
                    months_duration=exp.months_duration,
                )
                await self.unit_of_work.add(resume_experience)

        if education is not None:
            for edu in education:
                resume_education = ResumeEducation.factory(
                    resume_id=new_resume.id,
                    place=edu.place,
                    grade=edu.grade,
                    specialization=edu.specialization,
                    description=edu.description,
                )
                await self.unit_of_work.add(resume_education)

        if projects is not None:
            for proj in projects:
                resume_project = ResumeProject.factory(
                    resume_id=new_resume.id,
                    name=proj.name,
                    description=proj.description,
                )
                await self.unit_of_work.add(resume_project)

        if old_resume.up_resume_id is None:
            old_resume.up_resume_id = new_resume.id

        await self.unit_of_work.commit()

        new_experiences = await self.resume_experience_data_gateway.load_by_resume_id(new_resume.id)
        new_educations = await self.resume_education_data_gateway.load_by_resume_id(new_resume.id)
        new_projects = await self.resume_project_data_gateway.load_by_resume_id(new_resume.id)

        return EditResumeResponse(
            id=new_resume.id,
            position=new_resume.position,
            location=new_resume.location,
            about_me=new_resume.about_me,
            key_skills=new_resume.key_skills,
            experience_type=new_resume.experience_type,
            experience=[
                ExperienceItemResponse(
                    place=exp.place,
                    description=exp.description,
                    months_duration=exp.months_duration,
                )
                for exp in new_experiences
            ],
            education=[
                EducationItemResponse(
                    place=edu.place,
                    grade=edu.grade,
                    specialization=edu.specialization,
                    description=edu.description,
                )
                for edu in new_educations
            ],
            projects=[
                ProjectItemResponse(
                    name=proj.name,
                    description=proj.description,
                )
                for proj in new_projects
            ],
        )
