from http import HTTPStatus as status
from uuid import UUID

from django.shortcuts import get_object_or_404, get_list_or_404
from ninja import File, Router, UploadedFile

from api.v1.ping.schemas import PingOut
from api.v1.schemas import ForbiddenError, NotFoundError, UnauthorizedError
from api.v1.task.schemas import (
    HistorySubmissionOut,
    TaskAttachmentSchema,
    TaskOutSchema,
    TaskSubmissionOut,
    TaskStatusSchema,
)
from apps.achievement.models import Achievement, UserAchievement
from apps.competition.models import State
from apps.task.models import (
    Competition,
    CompetitionTask,
    CompetitionTaskAttachment,
    CompetitionTaskSubmission,
)
from apps.task.tasks import analyze_data_task

router = Router(tags=["competition"])


@router.post(
    "competitions/{competition_id}/start",
    description="Start a competition completing (open access to tasks)",
    response={
        status.OK: PingOut,
        status.UNAUTHORIZED: UnauthorizedError,
        status.NOT_FOUND: NotFoundError,
    },
)
def start_competition(request, competition_id: UUID) -> PingOut:
    competition = get_object_or_404(Competition, pk=competition_id)
    competition.participants.add(request.auth)
    state_obj, _ = State.objects.update_or_create(
        user=request.auth, competition=competition, state="started"
    )
    return status.OK, PingOut()


@router.get(
    "competitions/{competition_id}/tasks",
    description="Get all tasks of competition (works only if user started competition)",
    response={
        status.OK: list[TaskOutSchema],
        status.UNAUTHORIZED: UnauthorizedError,
        status.FORBIDDEN: ForbiddenError,
        status.NOT_FOUND: NotFoundError,
    },
)
def get_competition_tasks(
    request, competition_id: UUID
) -> list[TaskOutSchema]:
    competition = get_object_or_404(Competition, pk=competition_id)
    state = State.objects.filter(
        user=request.auth, competition=competition, state="started"
    ).first()
    if not state:
        return 403, ForbiddenError()

    return status.OK, CompetitionTask.objects.filter(
        competition=competition
    ).all()


@router.get(
    "competitions/{competition_id}/tasks/{task_id}",
    description="Get a task of competition task",
    response={
        status.OK: TaskOutSchema,
        status.UNAUTHORIZED: UnauthorizedError,
        status.FORBIDDEN: ForbiddenError,
        status.NOT_FOUND: NotFoundError,
    },
)
def get_task(request, competition_id: str, task_id: str) -> TaskOutSchema: ...


@router.post(
    "competitions/{competition_id}/tasks/{task_id}/submit",
    description="Submit task solution",
    response={
        status.OK: TaskSubmissionOut,
        status.UNAUTHORIZED: UnauthorizedError,
        status.FORBIDDEN: ForbiddenError,
        status.NOT_FOUND: NotFoundError,
    },
)
def submit_task(
    request,
    competition_id: str,
    task_id: str,
    content: UploadedFile = File(...),  # TODO: вот это надо переделать
) -> TaskSubmissionOut:
    user = request.auth
    competition = get_object_or_404(Competition, id=competition_id)
    task = get_object_or_404(
        CompetitionTask, competition=competition, id=task_id
    )

    if not CompetitionTaskSubmission.objects.filter(user=user).exists():
        first_steps_achievement = Achievement.objects.get(slug="first_steps")
        UserAchievement.objects.create(
            user=user, achievement=first_steps_achievement
        )

    total_attempts = CompetitionTaskSubmission.objects.filter(
        user=user, task=task
    ).count()
    if task.max_attempts == total_attempts:
        return status.FORBIDDEN, ForbiddenError()

    if task.type == CompetitionTask.CompetitionTaskType.INPUT:
        verdict = content.read() == task.correct_answer_file.read()
        submission = CompetitionTaskSubmission.objects.create(
            user=user,
            task=task,
            status=CompetitionTaskSubmission.StatusChoices.CHECKED,
            content=content,
            result={
                "correct": verdict
            },
            earned_points=task.points
        )
    if task.type == CompetitionTask.CompetitionTaskType.REVIEW:
        submission = CompetitionTaskSubmission.objects.create(
            user=user,
            task=task,
            status=CompetitionTaskSubmission.StatusChoices.SENT,
            content=content,
        )
        submission.send_on_review()
    if task.type == CompetitionTask.CompetitionTaskType.CHECKER:
        submission = CompetitionTaskSubmission.objects.create(
            user=user,
            task=task,
            status=CompetitionTaskSubmission.StatusChoices.CHECKING,
            content=content,
        )
        analyze_data_task.delay(submission_id=submission.id)

    return TaskSubmissionOut(submission_id=submission.id)


@router.get(
    "competitions/{competition_id}/tasks/{task_id}/history",
    response={
        status.OK: list[HistorySubmissionOut],
        status.UNAUTHORIZED: UnauthorizedError,
    },
)
def get_submissions_history(request, competition_id: UUID, task_id: UUID):
    task = get_object_or_404(
        CompetitionTask, competition_id=competition_id, id=task_id
    )
    submissions_history = CompetitionTaskSubmission.objects.filter(
        task=task, user=request.auth
    )

    return status.OK, submissions_history


@router.get(
    "competitions/{competition_id}/tasks/{task_id}/attachments",
    response={
        status.OK: list[TaskAttachmentSchema],
        status.UNAUTHORIZED: UnauthorizedError,
    },
)
def get_task_attachments(request, competition_id: UUID, task_id: UUID):
    task = get_object_or_404(CompetitionTask, id=task_id)
    return status.OK, CompetitionTaskAttachment.objects.filter(task=task).all()


@router.get(
    "competitions/{competition_id}/results",
    response={
        status.OK: list[TaskStatusSchema],
        status.UNAUTHORIZED: UnauthorizedError
    },
)
def get_competition_results(request, competition_id: UUID):
    tasks = get_list_or_404(CompetitionTask, competition_id=competition_id)

    data = []

    for task in tasks:
        submissions = CompetitionTaskSubmission.objects.filter(
            user=request.auth, task=task
        ).filter(status="checked").all()
        if not submissions:
            result = 0
        else:
            result = submissions[0].earned_points
        data.append(TaskStatusSchema(
            task_name=task.title,
            result=result
        ))

    return status.OK, data
