"""Pydantic schemas for the FlowPilot "What we know" session facts.

See FLOWPILOT-MIGRATION.md Section 4.2 for the data model rationale.
"""
from __future__ import annotations

from datetime import datetime
from typing import Literal
from uuid import UUID

from pydantic import BaseModel, Field

# AI-emittable source types are a subset (`user_note` is engineer-only).
AIEmittableSourceType = Literal["question", "diagnostic_check", "ai_synthesis"]
SourceType = Literal["question", "diagnostic_check", "user_note", "ai_synthesis"]


class SessionFactResponse(BaseModel):
    """A single fact card in the What-we-know panel."""
    id: UUID
    session_id: UUID
    text: str
    source_type: SourceType
    source_ref: UUID | None
    source_summary: str | None
    created_by: UUID
    created_at: datetime
    updated_at: datetime
    # `editable` is computed server-side so the client doesn't have to
    # re-encode the editability rule. It mirrors the PATCH endpoint's
    # 403 policy: only user_note and ai_synthesis facts are editable.
    editable: bool

    model_config = {"from_attributes": False}


class SessionFactListResponse(BaseModel):
    facts: list[SessionFactResponse]


class SessionFactCreateRequest(BaseModel):
    """Engineer-created manual fact (the "+ Add a note" affordance).

    The endpoint hard-codes source_type="user_note" — manual creation cannot
    spoof a question/check origin. Source-type-bound creation goes through
    `/promote` instead.
    """
    text: str = Field(..., min_length=1, max_length=2000)
    summary: str | None = Field(None, max_length=200)


class SessionFactUpdateRequest(BaseModel):
    """Edit an existing fact's text or summary.

    The endpoint returns 403 when the fact's source_type is `question` or
    `diagnostic_check` — those facts must be edited at the source item.
    """
    text: str | None = Field(None, min_length=1, max_length=2000)
    summary: str | None = Field(None, max_length=200)


class SessionFactPromoteRequest(BaseModel):
    """Promote a question answer / check result into a fact.

    Two modes:
    - **Direct**: caller provides `proposed_text` (and optionally `proposed_summary`).
      The fact is persisted as-is. Used by the AI [PROMOTE] marker path and by the
      engineer's "edit then save" affordance.
    - **Synthesize**: caller provides `raw_input` (the engineer's typed answer or
      the check output) and the server drafts `text`/`summary` via the
      FactSynthesisService. The draft is persisted immediately for now —
      the supervisor-staging review is a future enhancement (out of scope per
      Section 12).

    Exactly one of `proposed_text` or `raw_input` must be set.
    """
    source_type: AIEmittableSourceType
    source_ref: UUID | None = None
    proposed_text: str | None = Field(None, min_length=1, max_length=2000)
    proposed_summary: str | None = Field(None, max_length=200)
    raw_input: str | None = Field(None, min_length=1, max_length=10_000)
