from datetime import datetime
from typing import Any
from uuid import UUID

from pydantic import BaseModel, Field, model_validator

from src.models.question import Difficulty


class ExplanationResponse(BaseModel):
    """Explanation schema for API responses."""

    approach: str
    intuition: str
    common_pitfalls: list[dict[str, Any]] | None = None
    key_takeaways: list[str] | None = None
    time_complexity: str
    space_complexity: str
    complexity_explanation: str | None = None
    pattern_comparison: str | None = None

    model_config = {"from_attributes": True}


class SolutionResponse(BaseModel):
    """Solution schema for API responses."""

    id: UUID
    approach_name: str
    code: str
    language: str
    is_optimal: bool
    explanation: str | None = None

    model_config = {"from_attributes": True}


class CategoryBrief(BaseModel):
    """Brief category info for question responses."""

    id: UUID
    name: str
    slug: str

    model_config = {"from_attributes": True}


class PatternBrief(BaseModel):
    """Brief pattern info for question responses."""

    id: UUID
    name: str
    slug: str
    is_optimal: bool = False

    model_config = {"from_attributes": True}


class QuestionListItem(BaseModel):
    """Question summary for list views."""

    id: UUID
    title: str
    slug: str
    difficulty: Difficulty
    leetcode_id: int | None = None
    leetcode_url: str | None = None
    categories: list[CategoryBrief] = []
    patterns: list[PatternBrief] = []
    created_at: datetime

    model_config = {"from_attributes": True}

    @model_validator(mode="before")
    @classmethod
    def transform_patterns(cls, data: Any) -> Any:
        """Transform question_patterns to patterns with is_optimal flag."""
        if hasattr(data, "question_patterns"):
            # SQLAlchemy model - build patterns from question_patterns
            patterns = []
            for qp in data.question_patterns:
                patterns.append(
                    {
                        "id": qp.pattern.id,
                        "name": qp.pattern.name,
                        "slug": qp.pattern.slug,
                        "is_optimal": qp.is_optimal,
                    }
                )
            # Create a dict with all fields from data plus transformed patterns
            result = {
                "id": data.id,
                "title": data.title,
                "slug": data.slug,
                "difficulty": data.difficulty,
                "leetcode_id": data.leetcode_id,
                "leetcode_url": data.leetcode_url,
                "categories": data.categories,
                "patterns": patterns,
                "created_at": data.created_at,
            }
            return result
        return data


class VisibleTestCase(BaseModel):
    """Visible test case with full input and expected output."""

    id: int
    input: dict[str, Any]
    expected: Any


class HiddenTestInput(BaseModel):
    """Hidden test case input only (no expected value)."""

    id: int
    input: dict[str, Any]


class QuestionDetail(BaseModel):
    """Full question detail response."""

    id: UUID
    title: str
    slug: str
    difficulty: Difficulty
    description: str
    constraints: str | None = None
    examples: list[dict[str, Any]] | None = None
    leetcode_id: int | None = None
    leetcode_url: str | None = None
    function_signature: str | None = None
    visible_test_cases: list[VisibleTestCase] | None = None
    hidden_test_inputs: list[HiddenTestInput] | None = None
    categories: list[CategoryBrief] = []
    patterns: list[PatternBrief] = []
    explanation: ExplanationResponse | None = None
    solutions: list[SolutionResponse] = []
    created_at: datetime
    updated_at: datetime

    model_config = {"from_attributes": True}

    @model_validator(mode="before")
    @classmethod
    def transform_test_cases(cls, data: Any) -> Any:
        """Transform test_cases from DB format to visible/hidden split."""
        if hasattr(data, "__dict__"):
            # Transform patterns from question_patterns with is_optimal
            patterns = []
            if hasattr(data, "question_patterns"):
                for qp in data.question_patterns:
                    patterns.append(
                        {
                            "id": qp.pattern.id,
                            "name": qp.pattern.name,
                            "slug": qp.pattern.slug,
                            "is_optimal": qp.is_optimal,
                        }
                    )
            else:
                patterns = data.patterns

            # SQLAlchemy model - convert to dict
            values = {
                "id": data.id,
                "title": data.title,
                "slug": data.slug,
                "difficulty": data.difficulty,
                "description": data.description,
                "constraints": data.constraints,
                "examples": data.examples,
                "leetcode_id": data.leetcode_id,
                "leetcode_url": data.leetcode_url,
                "function_signature": data.function_signature,
                "categories": data.categories,
                "patterns": patterns,
                "explanation": data.explanation,
                "solutions": data.solutions,
                "created_at": data.created_at,
                "updated_at": data.updated_at,
            }
            test_cases = data.test_cases
        else:
            values = dict(data)
            test_cases = values.pop("test_cases", None)

        if test_cases:
            visible = test_cases.get("visible", [])
            hidden = test_cases.get("hidden", [])

            values["visible_test_cases"] = [
                {"id": i, "input": tc["input"], "expected": tc["expected"]}
                for i, tc in enumerate(visible)
            ]
            values["hidden_test_inputs"] = [
                {"id": len(visible) + i, "input": tc["input"]} for i, tc in enumerate(hidden)
            ]
        else:
            values["visible_test_cases"] = None
            values["hidden_test_inputs"] = None

        return values


class QuestionListResponse(BaseModel):
    """Paginated question list response."""

    items: list[QuestionListItem]
    total: int
    page: int
    limit: int
    pages: int


class HiddenTestOutput(BaseModel):
    """User's output for a hidden test case."""

    test_id: int
    output: Any


class SubmissionRequest(BaseModel):
    """Request to submit a solution for validation."""

    code: str = Field(..., min_length=1)
    hidden_outputs: list[HiddenTestOutput]


class TestResult(BaseModel):
    """Result of running a single test case."""

    test_id: int
    passed: bool
    input: dict[str, Any] | None = None
    expected: Any | None = None
    actual: Any
    error: str | None = None


class SubmissionResponse(BaseModel):
    """Response from submitting a solution."""

    passed: bool
    visible_results: list[TestResult]
    hidden_results: list[TestResult]
    total_passed: int
    total_tests: int
