import uuid
from datetime import date, datetime
from typing import Literal

from pydantic import BaseModel, ConfigDict, field_validator

from api.schemas.workplan_dependency import WorkplanDepStub
from api.workplan_status import normalize_workplan_status

WorkplanStatus = Literal[
    "proposed",
    "ready",
    "active",
    "blocked",
    "backlog",
    "finished",
    "archived",
]
ExecutionState = Literal["manual", "queued", "scheduled", "launching", "paused", "completed", "cancelled"]
LaunchMode = Literal["manual", "queued", "scheduled", "immediate"]
ConcurrencyMode = Literal["sequential", "parallel"]


class WorkplanStatusMixin(BaseModel):
    @field_validator("status", mode="before", check_fields=False)
    @classmethod
    def _normalise_status(cls, value):
        return normalize_workplan_status(value)


class WorkplanCreate(WorkplanStatusMixin):
    repo_id: uuid.UUID
    topic_id: uuid.UUID | None = None
    slug: str
    title: str
    description: str | None = None
    status: WorkplanStatus = "active"
    owner: str | None = None
    due_date: date | None = None
    planning_priority: str | None = None
    planning_order: int | None = None
    execution_state: ExecutionState = "manual"
    launch_mode: LaunchMode = "manual"
    concurrency_mode: ConcurrencyMode = "sequential"
    queue_rank: int | None = None
    execution_group: str | None = None
    scheduled_for: datetime | None = None
    repo_goal_id: uuid.UUID | None = None


class WorkplanUpdate(WorkplanStatusMixin):
    title: str | None = None
    description: str | None = None
    status: WorkplanStatus | None = None
    owner: str | None = None
    due_date: date | None = None
    planning_priority: str | None = None
    planning_order: int | None = None
    execution_state: ExecutionState | None = None
    launch_mode: LaunchMode | None = None
    concurrency_mode: ConcurrencyMode | None = None
    queue_rank: int | None = None
    execution_group: str | None = None
    scheduled_for: datetime | None = None
    topic_id: uuid.UUID | None = None
    repo_id: uuid.UUID | None = None
    repo_goal_id: uuid.UUID | None = None


class WorkplanFileBinding(BaseModel):
    workplan_id: uuid.UUID
    filename: str
    relative_path: str
    repo_slug: str
    archived: bool = False
    status: WorkplanStatus | None = None


class WorkplanBindingsSync(BaseModel):
    bindings: list[WorkplanFileBinding]


class WorkplanRead(WorkplanStatusMixin):
    model_config = ConfigDict(from_attributes=True)
    id: uuid.UUID
    repo_id: uuid.UUID
    topic_id: uuid.UUID | None = None
    repo_goal_id: uuid.UUID | None = None
    slug: str
    title: str
    description: str | None = None
    status: WorkplanStatus
    owner: str | None = None
    due_date: date | None = None
    planning_priority: str | None = None
    planning_order: int | None = None
    execution_state: ExecutionState = "manual"
    launch_mode: LaunchMode = "manual"
    concurrency_mode: ConcurrencyMode = "sequential"
    queue_rank: int | None = None
    execution_group: str | None = None
    scheduled_for: datetime | None = None
    backing_filename: str | None = None
    backing_relative_path: str | None = None
    backing_archived: bool | None = None
    backing_synced_at: datetime | None = None
    created_at: datetime
    updated_at: datetime


class WorkplanWithTaskCounts(WorkplanRead):
    tasks_total: int = 0
    tasks_wait: int = 0
    tasks_todo: int = 0
    tasks_progress: int = 0
    tasks_done: int = 0
    tasks_cancel: int = 0


class WorkplanWithDeps(WorkplanWithTaskCounts):
    """WorkplanWithTaskCounts enriched with dependency graph edges."""
    depends_on: list[WorkplanDepStub] = []
    blocks: list[WorkplanDepStub] = []
    blocked_reasons: list[dict] = []