from typing import Optional, Literal
from ninja import Schema
from uuid import UUID


class SubmissionIn(Schema):
    task_id: int
    html: Optional[str] = None
    css: Optional[str] = None
    js: Optional[str] = None
    conversation_id: Optional[UUID] = None


class SubmissionOut(Schema):
    id: UUID
    userid: int
    username: str
    task_id: int
    task_display: int
    task_title: str
    task_type: Literal["tutorial", "challenge"]
    score: float
    my_score: int = 0
    html: Optional[str] = None
    css: Optional[str] = None
    js: Optional[str] = None
    conversation_id: Optional[UUID] = None
    flag: Optional[str] = None
    nominated: bool = False
    submit_count: int = 0
    created: str
    modified: str

    @staticmethod
    def resolve_userid(obj):
        return obj.user.id

    @staticmethod
    def resolve_username(obj):
        return obj.user.username

    @staticmethod
    def resolve_task_id(obj):
        return obj.task.id

    @staticmethod
    def resolve_task_display(obj):
        return obj.task.display

    @staticmethod
    def resolve_task_title(obj):
        return obj.task.title

    @staticmethod
    def resolve_task_type(obj):
        return obj.task.task_type

    @staticmethod
    def resolve_my_score(obj):
        return getattr(obj, "my_score", None) or 0

    @staticmethod
    def resolve_submit_count(obj):
        return getattr(obj, "submit_count", None) or 0

    @staticmethod
    def resolve_created(obj):
        return obj.created.isoformat()

    @staticmethod
    def resolve_modified(obj):
        return obj.modified.isoformat()

    @staticmethod
    def get(submission, rating):
        return {
            "id": submission.id,
            "userid": submission.user.id,
            "username": submission.user.username,
            "task_id": submission.task.id,
            "task_display": submission.task.display,
            "task_title": submission.task.title,
            "task_type": submission.task.task_type,
            "score": submission.score,
            "my_score": rating.score if rating else 0,
            "html": submission.html,
            "css": submission.css,
            "js": submission.js,
            "conversation_id": submission.conversation_id,
            "flag": submission.flag,
            "nominated": submission.nominated,
            "created": submission.created.isoformat(),
            "modified": submission.modified.isoformat(),
        }


class RatingScoreIn(Schema):
    score: int


class SubmissionScoreOut(Schema):
    id: UUID
    score: float


class SubmissionFilter(Schema):
    task_id: Optional[int] = None
    task_type: Optional[Literal["tutorial", "challenge"]] = None
    username: Optional[str] = None
    user_id: Optional[int] = None
    flag: Optional[Literal["red", "blue", "green", "yellow", "any"]] = None
    score_min: Optional[float] = None
    score_max_exclusive: Optional[float] = None
    score_lt_threshold: Optional[float] = None
    nominated: Optional[bool] = None
    ordering: Optional[str] = None
    grouped: Optional[bool] = True


class FlagIn(Schema):
    flag: Optional[Literal["red", "blue", "green", "yellow"]] = None


class UserTag(Schema):
    username: str
    classname: str


class TopSubmission(Schema):
    submission_id: str  # UUID as string
    username: str
    classname: str
    score: float
    rating_count: int


class SubmissionCountBucket(Schema):
    count_1: int       # users with exactly 1 submission
    count_2: int       # users with exactly 2 submissions
    count_3: int       # users with exactly 3 submissions
    count_4_plus: int  # users with 4+ submissions


class FlagStats(Schema):
    red: int
    blue: int
    green: int
    yellow: int


class TaskStatsOut(Schema):
    submitted_count: int
    unsubmitted_count: int
    average_score: Optional[float]
    unrated_count: int
    nominated_count: int
    unsubmitted_users: list[UserTag]
    unrated_users: list[UserTag]
    submission_count_distribution: SubmissionCountBucket
    top_submissions: list[TopSubmission]
    flag_stats: FlagStats
    classes: list[str]

