# #region ValidationSchemas [C:3] [TYPE Module] [SEMANTICS pydantic, validation, schema, task, run]
# @BRIEF Pydantic v2 schemas for validation task management and run history API serialization.
# @LAYER API
# @RELATION DEPENDS_ON -> [EXT:Library:pydantic]

from datetime import datetime
from typing import Any, Literal

from pydantic import BaseModel, ConfigDict, Field


# #region SourceInput [C:1] [TYPE Class]
# @BRIEF Schema for creating a validation source from a dashboard ID or Superset URL.
# @RATIONALE v2 introduces typed source objects allowing both dashboard_id (existing numeric
#            reference) and dashboard_url (full Superset link that gets parsed/extracted) inputs.
# @REJECTED Keeping only dashboard_id rejected — dashboard_url enables sharing Superset links
#            directly without first resolving numeric IDs manually.
class SourceInput(BaseModel):
    type: Literal["dashboard_id", "dashboard_url"] = Field(
        ..., description="Source type: 'dashboard_id' for numeric IDs, 'dashboard_url' for full Superset URLs"
    )
    value: str = Field(..., description="Source value: numeric dashboard ID or full Superset dashboard URL")
# #endregion SourceInput


# #region SourceResponse [C:1] [TYPE Class]
# @BRIEF Schema for displaying a validation source in API responses.
class SourceResponse(BaseModel):
    id: str
    type: str
    value: str
    status: str = "valid"
    title: str | None = None
    resolved_dashboard_id: str | None = None
    last_error: str | None = None
    last_checked_at: datetime | None = None
    created_at: datetime | None = None

    model_config = ConfigDict(from_attributes=True)
# #endregion SourceResponse


# #region ValidationTaskCreate [C:2] [TYPE Class]
# @BRIEF Schema for creating a new validation task (policy). v2 adds sources, screenshot_enabled,
#        logs_enabled, execute_chart_data, llm_batch_size, concurrency_limit, and prompt_template.
# @RATIONALE All v2 fields are optional to support gradual migration. dashboard_ids is kept for
#            backward compat — when non-empty and sources is empty, auto-create ValidationSource rows.
# @REJECTED Breaking dashboard_ids removal rejected — existing UI callers and API clients still
#            send dashboard_ids; removing it would break migration without frontend changes.
class ValidationTaskCreate(BaseModel):
    name: str = Field(..., description="Human-readable task name")
    description: str | None = Field(None, description="Optional task description")
    environment_id: str = Field(..., description="Target Superset environment ID")
    dashboard_ids: list[str] = Field(default_factory=list, description="List of dashboard IDs (v1 compat — auto-creates ValidationSource rows if non-empty)")
    provider_id: str = Field(..., description="LLM provider ID — must be multimodal when screenshot_enabled=True")
    schedule_days: list[int] | None = Field(None, description="Days of week (0-6, 0=Sunday). Omit or empty for manual-only.")
    window_start: str | None = Field(None, description="Window start time, HH:MM format")
    window_end: str | None = Field(None, description="Window end time, HH:MM format")
    notify_owners: bool = Field(True, description="Notify dashboard owners on failure")
    custom_channels: list[str] | None = Field(None, description="Additional notification channels")
    alert_condition: str = Field("FAIL_ONLY", description="FAIL_ONLY, WARN_AND_FAIL, or ALWAYS")
    is_active: bool = Field(True, description="Whether the task is active")

    # v2 fields (all optional for gradual migration)
    screenshot_enabled: bool = Field(True, description="Enable screenshot-based validation (Path A)")
    logs_enabled: bool = Field(True, description="Enable log collection during validation")
    execute_chart_data: bool = Field(False, description="Execute chart data queries during validation")
    llm_batch_size: int = Field(1, description="Number of dashboards to send in a single LLM batch", ge=1)
    policy_dashboard_concurrency_limit: int = Field(3, description="Max concurrent dashboard validations for this policy", ge=1)
    prompt_template: str | None = Field(None, description="Custom prompt template override")
    sources: list[SourceInput] | None = Field(None, description="v2 source definitions (takes precedence over dashboard_ids)")
# #endregion ValidationTaskCreate


# #region ValidationTaskUpdate [C:2] [TYPE Class]
# @BRIEF Schema for updating an existing validation task (policy). Includes v2 fields.
# @RATIONALE All fields optional (partial update). When sources is provided, replaces all existing
#            ValidationSource rows for the policy.
class ValidationTaskUpdate(BaseModel):
    name: str | None = None
    description: str | None = None
    environment_id: str | None = None
    dashboard_ids: list[str] | None = None
    provider_id: str | None = None
    schedule_days: list[int] | None = None
    window_start: str | None = None
    window_end: str | None = None
    notify_owners: bool | None = None
    custom_channels: list[str] | None = None
    alert_condition: str | None = None
    is_active: bool | None = None

    # v2 fields
    screenshot_enabled: bool | None = None
    logs_enabled: bool | None = None
    execute_chart_data: bool | None = None
    llm_batch_size: int | None = None
    policy_dashboard_concurrency_limit: int | None = None
    prompt_template: str | None = None
    sources: list[SourceInput] | None = Field(None, description="Replace all sources when provided")
# #endregion ValidationTaskUpdate


# #region ValidationTaskResponse [C:2] [TYPE Class]
# @BRIEF Schema for validation task API responses — includes last run info and v2 fields.
class ValidationTaskResponse(BaseModel):
    id: str
    name: str
    description: str | None = Field(None, description="Optional task description")
    environment_id: str
    is_active: bool
    dashboard_ids: list[str]
    provider_id: str | None = None
    schedule_days: list[int] | None = None
    window_start: str | None = None
    window_end: str | None = None
    notify_owners: bool = True
    custom_channels: list[str] | None = None
    alert_condition: str = "FAIL_ONLY"
    created_at: datetime
    updated_at: datetime | None = None
    last_run_status: str | None = None
    last_run_at: datetime | None = None
    last_run_summary: dict | None = Field(None, description="Aggregated counts: {pass: N, warn: N, fail: N}")

    # v2 fields
    screenshot_enabled: bool = True
    logs_enabled: bool = True
    execute_chart_data: bool = False
    llm_batch_size: int = 1
    policy_dashboard_concurrency_limit: int = 3
    prompt_template: str | None = None
    sources: list[SourceResponse] = Field(default_factory=list, description="Resolved validation sources")

    model_config = ConfigDict(from_attributes=True)
# #endregion ValidationTaskResponse


# #region ValidationTaskListResponse [C:1] [TYPE Class]
# @BRIEF Schema for paginated task list response.
class ValidationTaskListResponse(BaseModel):
    items: list[ValidationTaskResponse] = []
    total: int = 0
    page: int = 1
    page_size: int = 20
# #endregion ValidationTaskListResponse


# #region TriggerRunResponse [C:1] [TYPE Class]
# @BRIEF Schema for trigger-run response — returns spawned task ID and run ID.
class TriggerRunResponse(BaseModel):
    task_id: str
    spawned_task_id: str
    run_id: str | None = Field(None, description="ValidationRun ID (v2)")
    status: str = "PENDING"
    message: str = "Validation task spawned"
# #endregion TriggerRunResponse


# #region RunResponse [C:1] [TYPE Class]
# @BRIEF Schema for v2 ValidationRun display (aggregate run, not individual record).
class RunResponse(BaseModel):
    id: str
    policy_id: str
    task_id: str | None = None
    status: str
    trigger: str = "manual"
    started_at: datetime | None = None
    finished_at: datetime | None = None
    dashboard_count: int = 0
    pass_count: int = 0
    warn_count: int = 0
    fail_count: int = 0
    unknown_count: int = 0
    created_at: datetime | None = None

    model_config = ConfigDict(from_attributes=True)
# #endregion RunResponse


# #region RunListResponse [C:1] [TYPE Class]
# @BRIEF Schema for paginated v2 run list response.
class RunListResponse(BaseModel):
    items: list[RunResponse] = []
    total: int = 0
    page: int = 1
    page_size: int = 20
# #endregion RunListResponse


# #region RecordResponse [C:1] [TYPE Class]
# @BRIEF Schema for a single ValidationRecord in cross-task runs listing.
class RecordResponse(BaseModel):
    id: str
    policy_id: str | None = None
    run_id: str | None = None
    dashboard_id: str
    dashboard_title: str | None = None
    environment_id: str | None = None
    status: str
    summary: str = ""
    timestamp: datetime | None = None
    execution_path: str | None = None
    screenshot_path: str | None = None
    screenshot_paths: list[str] = Field(default_factory=list)
    issues: list[dict[str, Any]] = Field(default_factory=list)
    raw_response: str | None = None
    dataset_health: dict[str, Any] | None = None
    chart_data_results: list[dict[str, Any]] = Field(default_factory=list)
    tab_screenshots: list[dict[str, Any]] = Field(default_factory=list)
    logs_sent_to_llm: list[str] = Field(default_factory=list)
    token_usage: dict[str, Any] | None = None
    timings: dict[str, Any] | None = None

    model_config = ConfigDict(from_attributes=True)
# #endregion RecordResponse


# #region RecordListResponse [C:1] [TYPE Class]
# @BRIEF Schema for paginated cross-task runs listing.
class RecordListResponse(BaseModel):
    items: list[RecordResponse] = []
    total: int = 0
    page: int = 1
    page_size: int = 20
# #endregion RecordListResponse


# #region RunDetailResponse [C:1] [TYPE Class]
# @BRIEF Schema for v2 run detail — ValidationRun + all its ValidationRecords.
class RunDetailResponse(BaseModel):
    run: RunResponse
    records: list[dict[str, Any]] = Field(default_factory=list)
# #endregion RunDetailResponse


# #endregion ValidationSchemas
