import uuid
from datetime import datetime
from typing import Any, Literal

from pydantic import BaseModel, ConfigDict, Field


class SourceRef(BaseModel):
    repo: str = Field(min_length=1, max_length=100)
    path: str = Field(min_length=1, max_length=1000)
    revision: str = Field(pattern=r"^[0-9a-f]{40,64}$")


class ReviewContractProject(BaseModel):
    contract: dict[str, Any]
    source: SourceRef
    decision_id: uuid.UUID | None = None
    workplan_id: uuid.UUID | None = None
    task_id: uuid.UUID | None = None
    required_for_decision: bool = False


class ReviewContractRead(BaseModel):
    model_config = ConfigDict(from_attributes=True)
    id: uuid.UUID
    contract_key: str
    schema_version: str
    contract_digest: str
    source_repo: str
    source_path: str
    source_revision: str
    document: dict[str, Any]
    active: bool
    required_for_decision: bool
    decision_id: uuid.UUID | None
    workplan_id: uuid.UUID | None
    task_id: uuid.UUID | None
    projected_at: datetime
    created_at: datetime
    updated_at: datetime


class ReviewReceiptSubmit(BaseModel):
    owner_id: str = Field(min_length=1, max_length=160)
    actor: str = Field(min_length=2, max_length=160)
    disposition: Literal["approve", "request_changes"]
    contract_digest: str = Field(pattern=r"^[0-9a-f]{64}$")
    artifact_hashes: dict[str, str] = Field(default_factory=dict)
    assertion_ids: list[str] = Field(default_factory=list)
    checks: list[dict[str, Any]] = Field(default_factory=list)
    note: str | None = Field(default=None, max_length=2000)
    source: SourceRef


class ReviewReceiptRead(BaseModel):
    model_config = ConfigDict(from_attributes=True)
    id: uuid.UUID
    contract_id: uuid.UUID
    owner_id: str
    actor: str
    disposition: str
    contract_digest: str
    receipt_digest: str
    artifact_hashes: dict[str, str]
    assertion_ids: list[str]
    checks: list[dict[str, Any]]
    note: str | None
    source_repo: str
    source_path: str
    source_revision: str
    submitted_at: datetime
    created_at: datetime


class OwnerReviewState(BaseModel):
    owner_id: str
    status: Literal["missing", "approved", "request_changes", "stale"]
    receipt_id: uuid.UUID | None = None
    receipt_digest: str | None = None
    submitted_at: datetime | None = None


class GateReviewState(BaseModel):
    gate_id: str
    policy: Literal["all_required"]
    owners: list[str]
    satisfied: bool


class ReviewAggregateRead(BaseModel):
    contract_key: str
    contract_digest: str
    satisfied: bool
    authorizes_execution: Literal[False] = False
    owners: list[OwnerReviewState]
    gates: list[GateReviewState]
