"""Finding-related schemas."""

import datetime
from typing import Any
from uuid import UUID
from ..model import Field
from ..enums import FindingType, QueryExecutionStatus
from .common import BaseResponse, BaseSchema, BaseEventResponse


class FindingCreateRequest(BaseSchema):
    """Base request schema for creating findings."""

    bucket_id: UUID = Field(..., description="ID of the associated bucket")
    data: dict[str, Any] = Field(..., description="Finding data")
    additional_data: dict[str, Any] | None = Field(
        None, description="Additional data for the finding"
    )
    finding_classification: dict[str, Any] | None = Field(
        None, description="Classification details of the finding"
    )
    item_id: UUID | None = Field(
        None, description="ID of the associated item in the external system"
    )
    item_type: str | UUID | None = Field(
        None, description="Item type as path string or UUID"
    )
    version: str | None = Field(
        None, description="Version of the item type (defaults to 'default')"
    )


class AddFindingRequest(FindingCreateRequest):
    """Request schema for creating ADD type findings."""


class RetireFindingRequest(FindingCreateRequest):
    """Request schema for creating RETIRE type findings."""


class UpdateFindingRequest(FindingCreateRequest):
    """Request schema for creating UPDATE type findings."""

    old_data: dict[str, Any] = Field(..., description="Previous state of the data")


class FindingResponse(BaseResponse):
    """Response schema for finding data."""

    id: UUID = Field(..., description="Unique identifier for the finding")
    bucket_id: UUID = Field(..., description="ID of the associated bucket")
    finding_type: FindingType = Field(..., description="Type of the finding")
    data: dict[str, Any] = Field(..., description="Finding data")
    old_data: dict[str, Any] | None = Field(
        None, description="Previous state of the data (for UPDATE findings)"
    )
    diff_keys: list[str] | None = Field(
        None,
        description="List of keys that differ between old and new data (for UPDATE findings)",
    )
    item_id: UUID | None = Field(
        default=None, description="ID of the associated item in the DSG Core system"
    )
    item_type_id: UUID | None = Field(
        default=None,
        description="ItemTypeId in the DSG Core system",
    )
    version: str | None = Field(default=None, description="Version of the ItemType")
    additional_data: dict[str, Any] | None = Field(None, description="Additional data")
    finding_classification: dict[str, Any] | None = Field(
        None, description="Classification details of the finding"
    )
    created_at: datetime.datetime = Field(..., description="Creation timestamp")
    updated_at: datetime.datetime | None = Field(
        None, description="Last update timestamp"
    )
    command_mappings_count: int = Field(
        0,
        description="Number of command-findings mappings associated with this finding",
    )
    matches_count: int = Field(
        0,
        description="Number of finding matches associated with this finding",
    )


class FindingListItemResponse(BaseResponse):
    """Lightweight finding payload for alignment table rendering."""

    id: UUID = Field(..., description="Unique identifier for the finding")
    bucket_id: UUID = Field(..., description="ID of the associated bucket")
    bucket_name: str = Field(..., description="Display name of the associated bucket")
    bucket_ordinal: int = Field(..., description="Ordinal of the associated bucket")
    bucket_type: str = Field(..., description="Type of the associated bucket")
    bucket_status: str = Field(..., description="Status of the associated bucket")
    finding_type: FindingType = Field(..., description="Type of the finding")
    item_id: UUID | None = Field(
        default=None, description="ID of the associated item in the DSG Core system"
    )
    item_type_id: UUID | None = Field(
        default=None,
        description="ItemTypeId in the DSG Core system",
    )
    version: str | None = Field(default=None, description="Version of the ItemType")
    additional_data: dict[str, Any] | None = Field(
        None,
        description="Auxiliary list metadata that is safe to render without the full finding detail payload",
    )
    finding_classification: dict[str, Any] | None = Field(
        None,
        description="Classification details of the finding",
    )
    display_data: dict[str, Any] = Field(
        default_factory=dict,
        description="Curated display fields promoted from finding data for list rendering",
    )
    created_at: datetime.datetime = Field(..., description="Creation timestamp")
    updated_at: datetime.datetime | None = Field(
        None, description="Last update timestamp"
    )
    command_mappings_count: int = Field(
        0,
        description="Number of command-findings mappings associated with this finding",
    )
    matches_count: int = Field(
        0,
        description="Number of finding matches associated with this finding",
    )
    has_detail: bool = Field(
        False,
        description="Whether the finding has heavy detail payload available via the detail endpoint",
    )


class PaginatedFindingListResponse(BaseResponse):
    """Paginated lightweight findings response."""

    items: list[FindingListItemResponse] = Field(
        default_factory=list,
        description="Lightweight findings for the requested page",
    )
    total: int = Field(..., description="Total number of findings matching the query")
    page: int = Field(..., description="Current page number")
    size: int = Field(..., description="Requested page size")


class PatchFindingAdditionalDataRequest(BaseSchema):
    """Request schema for patching additional_data of a finding."""

    additional_data: dict[str, Any] = Field(
        default_factory=dict,
        description="Additional data to replace the existing additional_data field of the finding",
        min_length=1,
    )


class FindingStatsResponse(BaseSchema):
    """Response schema for finding statistics."""

    total_findings: int = Field(..., description="Total number of findings")
    findings_by_type: dict[str, int] = Field(
        ..., description="Findings grouped by type"
    )
    recent_findings: list[FindingResponse] = Field(
        default_factory=list, description="Recent findings"
    )


class FindingMatchCreateRequest(BaseSchema):
    """Request schema for creating a finding match row."""

    item_id: UUID = Field(..., description="ID of the matched item")
    match_metadata: dict[str, Any] | None = Field(
        default=None,
        description="Additional metadata about this specific match",
    )


class FindingMatchResponse(BaseResponse):
    """Response schema for a finding match row."""

    id: int = Field(..., description="Unique identifier for the finding match row")
    finding_id: UUID = Field(..., description="ID of the associated finding")
    match_query_id: int = Field(..., description="ID of the query execution run")
    item_id: UUID = Field(..., description="ID of the matched item")
    match_metadata: dict[str, Any] | None = Field(
        None,
        description="Additional metadata about this specific match",
    )
    created_at: datetime.datetime = Field(..., description="Creation timestamp")


class FindingMatchQueryCreateRequest(BaseSchema):
    """Request schema for creating a finding match query execution."""

    as_of_date: datetime.date = Field(
        ..., description="Date snapshot used by the lookup query service"
    )
    query: dict[str, Any] = Field(
        default_factory=dict,
        description="Query used to find matches for the finding",
    )
    query_service_name: str | None = Field(
        default=None,
        description="Optional lookup/query service name (default is set server-side)",
    )
    query_service_version: str | None = Field(
        default=None,
        description="Version of the lookup/query service used",
    )
    status: QueryExecutionStatus = Field(
        default=QueryExecutionStatus.PENDING,
        description="Execution status of the lookup query run",
    )
    error_message: str | None = Field(
        default=None,
        description="Error details when query execution fails",
    )
    requested_by: str | None = Field(
        default=None,
        description="Actor/user/service principal that triggered this query",
    )
    correlation_id: str | None = Field(
        default=None,
        description="Correlation/request id for traceability",
    )
    duration_ms: int | None = Field(
        default=None,
        ge=0,
        description="Execution duration in milliseconds",
    )
    execution_metadata: dict[str, Any] | None = Field(
        default=None,
        description="Additional immutable audit metadata for this execution",
    )
    matches: list[FindingMatchCreateRequest] = Field(
        default_factory=list,
        description="Matched items returned by the query execution",
    )


class FindingMatchQueryUpdateRequest(BaseSchema):
    """Request schema for updating mutable query execution fields."""

    status: QueryExecutionStatus | None = Field(
        default=None,
        description="Execution status of the lookup query run",
    )
    error_message: str | None = Field(
        default=None,
        description="Error details when query execution fails",
    )
    duration_ms: int | None = Field(
        default=None,
        ge=0,
        description="Execution duration in milliseconds",
    )
    execution_metadata: dict[str, Any] | None = Field(
        default=None,
        description="Additional immutable audit metadata for this execution",
    )


class FindingMatchQueryResponse(BaseResponse):
    """Response schema for finding match query executions."""

    id: int = Field(..., description="Unique identifier for query execution")
    finding_id: UUID = Field(..., description="ID of the associated finding")
    as_of_date: datetime.date = Field(
        ..., description="Date snapshot used by the lookup query service"
    )
    executed_at: datetime.datetime = Field(
        ..., description="Timestamp when the lookup query was executed"
    )
    query: dict[str, Any] = Field(..., description="Lookup query payload")
    query_hash: str = Field(
        ..., description="Deterministic hash of canonical query payload and as_of_date"
    )
    query_service_name: str = Field(
        ..., description="Name of the lookup/query service used"
    )
    query_service_version: str | None = Field(
        None,
        description="Version of the lookup/query service used",
    )
    status: QueryExecutionStatus = Field(
        ..., description="Execution status of the lookup query run"
    )
    error_message: str | None = Field(
        None,
        description="Error details when query execution fails",
    )
    requested_by: str | None = Field(
        None,
        description="Actor/user/service principal that triggered this query",
    )
    correlation_id: str | None = Field(
        None,
        description="Correlation/request id for traceability",
    )
    duration_ms: int | None = Field(
        None,
        description="Execution duration in milliseconds",
    )
    execution_metadata: dict[str, Any] | None = Field(
        None,
        description="Additional immutable audit metadata for this execution",
    )
    match_count: int = Field(..., description="Number of matches found")
    created_at: datetime.datetime = Field(..., description="Creation timestamp")
    matches: list[FindingMatchResponse] = Field(
        default_factory=list,
        description="Matched items returned by the query execution",
    )


class QueryProviderResponse(BaseResponse):
    """Response schema for query provider metadata."""

    name: str = Field(..., description="Provider name/identifier")
    description: str = Field(
        ..., description="Human-readable description of the provider"
    )
    supports_temporal: bool = Field(
        ..., description="Whether the provider supports temporal (as_of_date) queries"
    )
    supports_filters: bool = Field(
        ..., description="Whether the provider supports filter conditions"
    )
    example_query: dict[str, Any] = Field(
        default_factory=dict,
        description="Example query payload structure for this provider",
    )


class FindingEventResponse(BaseEventResponse):
    """Response schema for finding event data."""

    finding_id: UUID = Field(..., description="ID of the associated finding")
