from decimal import Decimal
from http import HTTPStatus
from typing import Annotated

from dishka import AsyncContainer, FromDishka
from dishka.integrations.fastapi import DishkaRoute
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query, Request
from fastapi.security import HTTPBearer
from pydantic import BaseModel, Field

from template_project.application.common.enums import EducationGrade, ExperienceType
from template_project.application.resume.entity import ResumeId
from template_project.application.resume.errors import ResumeDoesBelongUserError, ResumeNotFoundError
from template_project.application.resume.interactors.add import (
    AddResumeInteractor,
    EducationInput,
    ExperienceInput,
    ProjectInput,
)
from template_project.application.resume.interactors.edit import (
    EditResumeInteractor,
    EducationInput as EditEducationInput,
    ExperienceInput as EditExperienceInput,
    ProjectInput as EditProjectInput,
)
from template_project.application.resume.interactors.get import (
    GetResumeHistoryInteractor,
    GetResumeInteractor,
    GetResumeListInteractor,
)
from template_project.application.resume.interactors.prediction_pipeline import (
    PredictResumeRequest,
    ResumePredictionInteractor,
)

security = HTTPBearer()
router = APIRouter(route_class=DishkaRoute, tags=["Resume"], dependencies=[Depends(security)])


class ExperienceItem(BaseModel):
    place: str = Field(min_length=1, max_length=200, description="Company or organization name", examples=["T-bank"])
    description: str = Field(
        min_length=1, max_length=2000, description="Job description", examples=["some description lorem ipsum"]
    )
    months_duration: int = Field(ge=1, description="Duration in months", examples=[12])

    model_config = {
        "json_schema_extra": {
            "example": {
                "place": "T-bank",
                "description": "some description lorem ipsum",
                "months_duration": 12,
            }
        }
    }


class EducationItem(BaseModel):
    place: str = Field(
        min_length=1, max_length=200, description="Educational institution name", examples=["Central university"]
    )
    grade: EducationGrade = Field(description="Education grade", examples=[EducationGrade.BACHELOR])
    specialization: str = Field(min_length=1, max_length=200, description="Field of study", examples=["IT guy"])
    description: str | None = Field(
        None,
        max_length=2000,
        description="Additional description (optional)",
        examples=["optional field, if user want add something"],
    )

    model_config = {
        "json_schema_extra": {
            "example": {
                "place": "Central university",
                "grade": "bachelor",
                "specialization": "IT guy",
                "description": "optional field, if user want add something",
            }
        }
    }


class ProjectItem(BaseModel):
    name: str = Field(min_length=1, max_length=200, description="Project name", examples=["Rekomenci fluon"])
    description: str = Field(
        min_length=1, max_length=2000, description="Project description", examples=["some description"]
    )

    model_config = {
        "json_schema_extra": {
            "example": {
                "name": "Rekomenci fluon",
                "description": "some description",
            }
        }
    }


class CreateResumeRequest(BaseModel):
    position: str = Field(min_length=1, max_length=200, description="Job position", examples=["Python Developer"])
    about_me: str = Field(
        min_length=1,
        max_length=2000,
        description="About me section",
        examples=["Experienced Python developer with 5 years of experience"],
    )
    key_skills: list[str] = Field(
        min_length=1, description="List of key skills", examples=[["Python", "FastAPI", "PostgreSQL"]]
    )
    experience_type: ExperienceType = Field(description="Experience type", examples=[ExperienceType.BETWEEN_3_AND_6])
    location: str = Field(min_length=1, max_length=100, description="Location", examples=["Moscow"])
    experience: list[ExperienceItem] = Field(default_factory=list, description="Work experience list")
    education: list[EducationItem] = Field(default_factory=list, description="Education list")
    projects: list[ProjectItem] = Field(default_factory=list, description="Projects list")

    model_config = {
        "json_schema_extra": {
            "example": {
                "position": "Python Developer",
                "about_me": "Experienced Python developer with 5 years of experience",
                "key_skills": ["Python", "FastAPI", "PostgreSQL", "Docker"],
                "experience_type": "between3And6",
                "location": "Moscow",
                "experience": [
                    {
                        "place": "T-bank",
                        "description": "some description lorem ipsum",
                        "months_duration": 12,
                    }
                ],
                "education": [
                    {
                        "place": "Central university",
                        "grade": "bachelor",
                        "specialization": "IT guy",
                        "description": "optional field, if user want add something",
                    }
                ],
                "projects": [
                    {
                        "name": "Rekomenci fluon",
                        "description": "some description",
                    }
                ],
            }
        }
    }


class CreateResumeResponse(BaseModel):
    resume_id: ResumeId = Field(description="Created resume ID")

    model_config = {"json_schema_extra": {"example": {"resume_id": "01234567-89ab-cdef-0123-456789abcdef"}}}


class SalaryPrediction(BaseModel):
    from_salary: Decimal = Field(description="Minimum predicted salary", examples=[Decimal(100000)])
    to_salary: Decimal = Field(description="Maximum predicted salary", examples=[Decimal(150000)])
    recommended_skills: list[str] = Field(description="Recommended skills to add", examples=[["Kubernetes", "Redis"]])

    model_config = {
        "json_schema_extra": {
            "example": {
                "from_salary": "100000",
                "to_salary": "150000",
                "recommended_skills": ["Kubernetes", "Redis"],
            }
        }
    }


class ResumeResponse(BaseModel):
    id: ResumeId = Field(description="Resume ID")
    position: str = Field(description="Job position")
    location: str = Field(description="Location")
    about_me: str = Field(description="About me section")
    key_skills: list[str] = Field(description="List of key skills")
    experience_type: ExperienceType = Field(description="Experience type")
    experience: list[ExperienceItem] = Field(description="Work experience list")
    education: list[EducationItem] = Field(description="Education list")
    projects: list[ProjectItem] = Field(description="Projects list")
    prediction: SalaryPrediction | None = Field(None, description="Salary prediction (can be null)")

    model_config = {
        "json_schema_extra": {
            "example": {
                "position": "Python Developer",
                "location": "Moscow",
                "about_me": "Experienced Python developer with 5 years of experience",
                "key_skills": ["Python", "FastAPI", "PostgreSQL", "Docker"],
                "experience_type": "between3And6",
                "experience": [
                    {
                        "place": "T-bank",
                        "description": "some description lorem ipsum",
                        "months_duration": 12,
                    }
                ],
                "education": [
                    {
                        "place": "Central university",
                        "grade": "bachelor",
                        "specialization": "IT guy",
                        "description": "optional field, if user want add something",
                    }
                ],
                "projects": [
                    {
                        "name": "Rekomenci fluon",
                        "description": "some description",
                    }
                ],
                "prediction": {
                    "from_salary": "100000",
                    "to_salary": "150000",
                    "recommended_skills": ["Kubernetes", "Redis"],
                },
            }
        }
    }


class ResumeListItem(BaseModel):
    id: ResumeId = Field(description="Resume ID")
    position: str = Field(description="Job position")
    location: str = Field(description="Location")
    about_me: str = Field(description="About me section")
    key_skills: list[str] = Field(description="List of key skills")
    experience_type: ExperienceType = Field(description="Experience type")
    experience: list[ExperienceItem] = Field(description="Work experience list")
    education: list[EducationItem] = Field(description="Education list")
    projects: list[ProjectItem] = Field(description="Projects list")
    prediction: SalaryPrediction | None = Field(None, description="Salary prediction (can be null)")

    model_config = {
        "json_schema_extra": {
            "example": {
                "position": "Python Developer",
                "location": "Moscow",
                "about_me": "Experienced Python developer with 5 years of experience",
                "key_skills": ["Python", "FastAPI", "PostgreSQL"],
                "experience_type": "between3And6",
                "experience": [
                    {
                        "place": "T-bank",
                        "description": "some description lorem ipsum",
                        "months_duration": 12,
                    }
                ],
                "education": [
                    {
                        "place": "Central university",
                        "grade": "bachelor",
                        "specialization": "IT guy",
                        "description": "optional field, if user want add something",
                    }
                ],
                "projects": [
                    {
                        "name": "Rekomenci fluon",
                        "description": "some description",
                    }
                ],
            }
        }
    }


class GetResumeListRequest(BaseModel):
    limit: int = Field(ge=1, le=100, description="Number of resumes to return", examples=[10])
    offset: int = Field(ge=0, description="Number of resumes to skip", examples=[0])


class GetResumeListResponse(BaseModel):
    resumes: list[ResumeListItem] = Field(description="List of resumes")

    model_config = {
        "json_schema_extra": {
            "example": {
                "resumes": [
                    {
                        "position": "Python Developer",
                        "location": "Moscow",
                        "about_me": "Experienced Python developer",
                        "key_skills": ["Python", "FastAPI"],
                        "experience_type": "between3And6",
                        "experience": [
                            {
                                "place": "T-bank",
                                "description": "some description lorem ipsum",
                                "months_duration": 12,
                            }
                        ],
                        "education": [
                            {
                                "place": "Central university",
                                "grade": "bachelor",
                                "specialization": "IT guy",
                                "description": "optional field, if user want add something",
                            }
                        ],
                        "projects": [
                            {
                                "name": "Rekomenci fluon",
                                "description": "some description",
                            }
                        ],
                    }
                ]
            }
        }
    }


class GetResumeHistoryRequest(BaseModel):
    limit: int = Field(ge=1, le=100, description="Number of resumes to return", examples=[10])
    offset: int = Field(ge=0, description="Number of resumes to skip", examples=[0])


class GetResumeHistoryResponse(BaseModel):
    resumes: list[ResumeListItem] = Field(description="List of resume history items")

    model_config = {
        "json_schema_extra": {
            "example": {
                "resumes": [
                    {
                        "position": "Python Developer",
                        "location": "Moscow",
                        "about_me": "Experienced Python developer",
                        "key_skills": ["Python", "FastAPI"],
                        "experience_type": "between3And6",
                        "experience": [
                            {
                                "place": "T-bank",
                                "description": "some description lorem ipsum",
                                "months_duration": 12,
                            }
                        ],
                        "education": [
                            {
                                "place": "Central university",
                                "grade": "bachelor",
                                "specialization": "IT guy",
                                "description": "optional field, if user want add something",
                            }
                        ],
                        "projects": [
                            {
                                "name": "Rekomenci fluon",
                                "description": "some description",
                            }
                        ],
                    }
                ]
            }
        }
    }


@router.post(
    "/resume",
    summary="Create resume",
    description="Create a new resume with position, about me, key skills and experience type",
    responses={
        200: {"description": "Resume created successfully", "model": CreateResumeResponse},
        401: {"description": "Unauthorized - invalid or missing token"},
    },
)
async def create_resume(
    request: CreateResumeRequest,
    background_tasks: BackgroundTasks,
    fastapi_request: Request,
    interactor: FromDishka[AddResumeInteractor],
) -> CreateResumeResponse:
    experience = (
        [
            ExperienceInput(place=exp.place, description=exp.description, months_duration=exp.months_duration)
            for exp in request.experience
        ]
        if request.experience
        else None
    )
    education = (
        [
            EducationInput(
                place=edu.place, grade=edu.grade, specialization=edu.specialization, description=edu.description
            )
            for edu in request.education
        ]
        if request.education
        else None
    )
    projects = (
        [ProjectInput(name=proj.name, description=proj.description) for proj in request.projects]
        if request.projects
        else None
    )

    interactor_response = await interactor.execute(
        position=request.position,
        location=request.location,
        about_me=request.about_me,
        key_skills=request.key_skills,
        experience_type=request.experience_type,
        experience=experience,
        education=education,
        projects=projects,
    )

    async def run_prediction(resume_id: ResumeId, container: AsyncContainer) -> None:
        async with container() as request_container:
            prediction_interactor = await request_container.get(ResumePredictionInteractor)
            await prediction_interactor.execute(PredictResumeRequest(resume_id=resume_id))

    background_tasks.add_task(
        run_prediction,
        interactor_response,
        fastapi_request.app.state.dishka_container,
    )

    return CreateResumeResponse(
        resume_id=interactor_response,
    )


@router.get(
    "/resume/list",
    summary="Get resume list",
    description="Get paginated list of latest resumes (without up_resume_id)",
    responses={
        200: {"description": "Resume list retrieved successfully", "model": GetResumeListResponse},
        401: {"description": "Unauthorized - invalid or missing token"},
    },
)
async def get_resume_list(
    limit: Annotated[int, Query(ge=1, le=100)],
    offset: Annotated[int, Query(ge=0)],
    interactor: FromDishka[GetResumeListInteractor],
) -> GetResumeListResponse:
    interactor_response = await interactor.execute(limit=limit, offset=offset)
    return GetResumeListResponse(
        resumes=[
            ResumeListItem(
                id=r.id,
                position=r.position,
                location=r.location,
                about_me=r.about_me,
                key_skills=r.key_skills,
                experience_type=r.experience_type,
                experience=[
                    ExperienceItem(
                        place=exp.place,
                        description=exp.description,
                        months_duration=exp.months_duration,
                    )
                    for exp in r.experience
                ],
                education=[
                    EducationItem(
                        place=edu.place,
                        grade=edu.grade,
                        specialization=edu.specialization,
                        description=edu.description,
                    )
                    for edu in r.education
                ],
                projects=[
                    ProjectItem(
                        name=proj.name,
                        description=proj.description,
                    )
                    for proj in r.projects
                ],
                prediction=SalaryPrediction(
                    from_salary=r.prediction.from_salary,
                    to_salary=r.prediction.to_salary,
                    recommended_skills=r.prediction.recommended_skills,
                )
                if r.prediction is not None
                else None,
            )
            for r in interactor_response
        ]
    )


@router.get(
    "/resume/{resume_id}",
    summary="Get resume",
    description="Get resume by ID with optional salary prediction",
    responses={
        200: {"description": "Resume retrieved successfully", "model": ResumeResponse},
        401: {"description": "Unauthorized - invalid or missing token"},
        404: {"description": "Resume not found"},
        403: {"descriptipn": "The resume does not belong to you"},
    },
)
async def get_resume(
    resume_id: ResumeId,
    interactor: FromDishka[GetResumeInteractor],
) -> ResumeResponse:
    try:
        interactor_response = await interactor.execute(resume_id)
    except ResumeNotFoundError as error:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND,
            detail="Resume not found",
        ) from error
    except ResumeDoesBelongUserError as error:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND,
            detail="The resume does not belong to you",
        ) from error

    return ResumeResponse(
        id=interactor_response.id,
        position=interactor_response.position,
        location=interactor_response.location,
        about_me=interactor_response.about_me,
        key_skills=interactor_response.key_skills,
        experience_type=interactor_response.experience_type,
        experience=[
            ExperienceItem(
                place=exp.place,
                description=exp.description,
                months_duration=exp.months_duration,
            )
            for exp in interactor_response.experience
        ],
        education=[
            EducationItem(
                place=edu.place,
                grade=edu.grade,
                specialization=edu.specialization,
                description=edu.description,
            )
            for edu in interactor_response.education
        ],
        projects=[
            ProjectItem(
                name=proj.name,
                description=proj.description,
            )
            for proj in interactor_response.projects
        ],
        prediction=SalaryPrediction(
            from_salary=interactor_response.prediction.from_salary,
            to_salary=interactor_response.prediction.to_salary,
            recommended_skills=interactor_response.prediction.recommended_skills,
        )
        if interactor_response.prediction is not None
        else None,
    )


class PatchResumeRequest(BaseModel):
    position: str | None = Field(
        None, min_length=1, max_length=200, description="Job position", examples=["Python Developer"]
    )
    location: str | None = Field(None, min_length=1, max_length=100, description="Location", examples=["Moscow"])
    about_me: str | None = Field(
        None, min_length=1, max_length=2000, description="About me section", examples=["Experienced Python developer"]
    )
    key_skills: list[str] | None = Field(
        None, min_length=1, description="List of key skills", examples=[["Python", "FastAPI", "PostgreSQL"]]
    )
    experience_type: ExperienceType | None = Field(
        None, description="Experience type", examples=[ExperienceType.BETWEEN_3_AND_6]
    )
    experience: list[ExperienceItem] | None = Field(None, description="Work experience list")
    education: list[EducationItem] | None = Field(None, description="Education list")
    projects: list[ProjectItem] | None = Field(None, description="Projects list")

    model_config = {
        "json_schema_extra": {
            "example": {
                "position": "Python Developer",
                "location": "Moscow",
                "about_me": "Experienced Python developer with 5 years of experience",
                "key_skills": ["Python", "FastAPI", "PostgreSQL", "Docker"],
                "experience_type": "between3And6",
                "experience": [
                    {
                        "place": "T-bank",
                        "description": "some description lorem ipsum",
                        "months_duration": 12,
                    }
                ],
                "education": [
                    {
                        "place": "Central university",
                        "grade": "bachelor",
                        "specialization": "IT guy",
                        "description": "optional field, if user want add something",
                    }
                ],
                "projects": [
                    {
                        "name": "Rekomenci fluon",
                        "description": "some description",
                    }
                ],
            }
        }
    }


class PatchResumeResponse(BaseModel):
    id: ResumeId = Field(description="Resume ID")
    position: str = Field(description="Job position")
    location: str = Field(description="Location")
    about_me: str = Field(description="About me section")
    key_skills: list[str] = Field(description="List of key skills")
    experience_type: ExperienceType = Field(description="Experience type")
    experience: list[ExperienceItem] = Field(description="Work experience list")
    education: list[EducationItem] = Field(description="Education list")
    projects: list[ProjectItem] = Field(description="Projects list")

    model_config = {
        "json_schema_extra": {
            "example": {
                "position": "Python Developer",
                "location": "Moscow",
                "about_me": "Experienced Python developer with 5 years of experience",
                "key_skills": ["Python", "FastAPI", "PostgreSQL", "Docker"],
                "experience_type": "between3And6",
                "experience": [
                    {
                        "place": "T-bank",
                        "description": "some description lorem ipsum",
                        "months_duration": 12,
                    }
                ],
                "education": [
                    {
                        "place": "Central university",
                        "grade": "bachelor",
                        "specialization": "IT guy",
                        "description": "optional field, if user want add something",
                    }
                ],
                "projects": [
                    {
                        "name": "Rekomenci fluon",
                        "description": "some description",
                    }
                ],
            }
        }
    }


@router.get(
    "/resume/{resume_id}/history",
    summary="Get resume history",
    description="Get all versions of a resume by following down_resume_id chain",
    responses={
        200: {"description": "Resume history retrieved successfully", "model": GetResumeHistoryResponse},
        401: {"description": "Unauthorized - invalid or missing token"},
        404: {"description": "Resume not found"},
        403: {"description": "The resume does not belong to you"},
    },
)
async def get_resume_history(
    resume_id: ResumeId,
    interactor: FromDishka[GetResumeHistoryInteractor],
) -> GetResumeHistoryResponse:
    try:
        interactor_response = await interactor.execute(resume_id)
    except ResumeNotFoundError as error:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND,
            detail="Resume not found",
        ) from error
    except ResumeDoesBelongUserError as error:
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN,
            detail="The resume does not belong to you",
        ) from error

    return GetResumeHistoryResponse(
        resumes=[
            ResumeListItem(
                id=r.id,
                position=r.position,
                location=r.location,
                about_me=r.about_me,
                key_skills=r.key_skills,
                experience_type=r.experience_type,
                experience=[
                    ExperienceItem(
                        place=exp.place,
                        description=exp.description,
                        months_duration=exp.months_duration,
                    )
                    for exp in r.experience
                ],
                education=[
                    EducationItem(
                        place=edu.place,
                        grade=edu.grade,
                        specialization=edu.specialization,
                        description=edu.description,
                    )
                    for edu in r.education
                ],
                projects=[
                    ProjectItem(
                        name=proj.name,
                        description=proj.description,
                    )
                    for proj in r.projects
                ],
                prediction=SalaryPrediction(
                    from_salary=r.prediction.from_salary,
                    to_salary=r.prediction.to_salary,
                    recommended_skills=r.prediction.recommended_skills,
                )
                if r.prediction is not None
                else None,
            )
            for r in interactor_response
        ]
    )


@router.patch(
    "/resume/{resume_id}",
    summary="Update resume",
    description="Update resume fields. All fields are optional.",
    responses={
        200: {"description": "Resume updated successfully", "model": PatchResumeResponse},
        401: {"description": "Unauthorized - invalid or missing token"},
        404: {"description": "Resume not found"},
        403: {"descriptipn": "The resume does not belong to you"},
    },
)
async def patch_resume(
    resume_id: ResumeId,
    request: PatchResumeRequest,
    background_tasks: BackgroundTasks,
    fastapi_request: Request,
    interactor: FromDishka[EditResumeInteractor],
) -> PatchResumeResponse:
    try:
        experience = (
            [
                EditExperienceInput(place=exp.place, description=exp.description, months_duration=exp.months_duration)
                for exp in request.experience
            ]
            if request.experience is not None
            else None
        )
        education = (
            [
                EditEducationInput(
                    place=edu.place, grade=edu.grade, specialization=edu.specialization, description=edu.description
                )
                for edu in request.education
            ]
            if request.education is not None
            else None
        )
        projects = (
            [EditProjectInput(name=proj.name, description=proj.description) for proj in request.projects]
            if request.projects is not None
            else None
        )

        interactor_response = await interactor.execute(
            resume_id=resume_id,
            position=request.position,
            location=request.location,
            about_me=request.about_me,
            key_skills=request.key_skills,
            experience_type=request.experience_type,
            experience=experience,
            education=education,
            projects=projects,
        )

        async def run_prediction(resume_id: ResumeId, container: AsyncContainer) -> None:
            async with container() as request_container:
                prediction_interactor = await request_container.get(ResumePredictionInteractor)
                await prediction_interactor.execute(PredictResumeRequest(resume_id=resume_id))

        background_tasks.add_task(
            run_prediction,
            interactor_response.id,
            fastapi_request.app.state.dishka_container,
        )
    except ResumeDoesBelongUserError as error:
        raise HTTPException(
            status_code=HTTPStatus.FORBIDDEN,
            detail="The resume does not belong to you",
        ) from error
    except ResumeNotFoundError as error:
        raise HTTPException(
            status_code=HTTPStatus.NOT_FOUND,
            detail="Resume not found",
        ) from error

    return PatchResumeResponse(
        id=interactor_response.id,
        position=interactor_response.position,
        location=interactor_response.location,
        about_me=interactor_response.about_me,
        key_skills=interactor_response.key_skills,
        experience_type=interactor_response.experience_type,
        experience=[
            ExperienceItem(
                place=exp.place,
                description=exp.description,
                months_duration=exp.months_duration,
            )
            for exp in interactor_response.experience
        ],
        education=[
            EducationItem(
                place=edu.place,
                grade=edu.grade,
                specialization=edu.specialization,
                description=edu.description,
            )
            for edu in interactor_response.education
        ],
        projects=[
            ProjectItem(
                name=proj.name,
                description=proj.description,
            )
            for proj in interactor_response.projects
        ],
    )
