"""Alignment-related schemas."""

import datetime
from enum import StrEnum
from uuid import UUID
from ..model import Field
from .common import BaseResponse, BaseSchema


class AlignmentProcessingStatus(StrEnum):
    PENDING = "pending"
    IN_PROGRESS = "in_progress"
    READY = "ready"
    FAILED = "failed"


class AlignmentWorkflowStatus(StrEnum):
    NOT_STARTED = "not_started"
    IN_PROGRESS = "in_progress"
    CLOSED = "closed"


AlignmentStatus = AlignmentProcessingStatus


class AlignmentBase(BaseSchema):
    """Base schema for alignment data."""

    name: str = Field(
        ..., description="Name of the alignment", min_length=1, max_length=255
    )
    description: str | None = Field(None, description="Description of the alignment")
    from_version: str | None = Field(
        None, description="Identifier of the alignment start point"
    )
    to_version: str | None = Field(
        None, description="Identifier of the alignment end point"
    )


class AlignmentCreateRequest(AlignmentBase):
    """Request schema for creating an alignment."""

    alignment_type_id: int = Field(..., description="ID of the alignment type")


class AlignmentUpdateRequest(BaseSchema):
    """Request schema for updating an alignment."""

    name: str | None = Field(
        None, description="New name of the alignment", min_length=1, max_length=255
    )
    description: str | None = Field(
        None, description="New description of the alignment"
    )
    from_version: str | None = Field(
        None, description="New identifier of the alignment start point"
    )
    to_version: str | None = Field(
        None, description="New identifier of the alignment end point"
    )


class AlignmentCloseRequest(BaseSchema):
    """Request schema for explicitly closing an alignment."""

    pass


class AlignmentMetrics(BaseSchema):
    """Metrics for alignment data."""

    buckets_count: int = Field(0, description="Number of buckets in the alignment")
    findings_count: int = Field(0, description="Number of findings in the alignment")
    command_groups_count: int = Field(
        0, description="Number of command groups in the alignment"
    )
    commands_count: int = Field(0, description="Number of commands in the alignment")
    pending_findings_count: int = Field(
        0, description="Number of findings with no mapped commands"
    )
    incomplete_buckets_count: int = Field(
        0, description="Number of buckets not yet resolved or closed"
    )


class AlignmentProcessingProgress(BaseSchema):
    """Normalized progress snapshot persisted from the external upload task."""

    provider: str = Field(..., description="External provider that reported the task")
    task_id: str | None = Field(None, description="External upload task identifier")
    task_status: str | None = Field(None, description="Normalized external task status")
    current_step: str | None = Field(
        None, description="Normalized current processing step key"
    )
    step_label: str | None = Field(None, description="Current step label")
    step_state: str | None = Field(None, description="Current step execution state")
    processing_message: str | None = Field(
        None, description="User-visible processing progress message"
    )
    updated_at: str | None = Field(
        None, description="Last upstream progress update timestamp"
    )
    processing_phase: str | None = Field(
        None,
        description="Normalized high-level processing phase reported by the upstream task",
    )
    bucket_progress: dict[str, int] | None = Field(
        None,
        description="Bucket post-processing progress summary reported by the upstream task",
    )
    failure_summary: dict[str, object] | None = Field(
        None,
        description="Structured summary of bucket-level failures reported by the upstream task",
    )


class AlignmentResponse(AlignmentBase, BaseResponse):
    """Response schema for alignment data."""

    id: UUID = Field(..., description="Unique identifier for the alignment")
    alignment_type_id: int = Field(..., description="ID of the alignment type")
    status: AlignmentProcessingStatus = Field(
        ...,
        description="Backward-compatible alias of processingStatus",
    )
    processing_status: AlignmentProcessingStatus = Field(
        ...,
        description="Processing/readiness status of the alignment",
    )
    workflow_status: AlignmentWorkflowStatus = Field(
        ...,
        description="Explicit user workflow status for the alignment",
    )
    processing_started_at: datetime.datetime | None = Field(
        None, description="Timestamp when alignment processing began"
    )
    processing_finished_at: datetime.datetime | None = Field(
        None, description="Timestamp when alignment processing finished"
    )
    last_error: str | None = Field(
        None, description="Last error encountered during processing"
    )
    task_id: str | None = Field(
        None, description="External upload task identifier"
    )
    external_upload_status: str | None = Field(
        None, description="Last-known status from the external upload task"
    )
    processing_progress: AlignmentProcessingProgress | None = Field(
        None,
        description="Persisted normalized processing progress snapshot",
    )
    created_at: datetime.datetime = Field(..., description="Creation timestamp")
    created_by: UUID = Field(..., description="User UID who created the alignment")
    updated_at: datetime.datetime | None = Field(
        None, description="Last update timestamp"
    )
    metrics: AlignmentMetrics | None = Field(
        None, description="Metrics for the alignment"
    )


class AlignmentTypeBase(BaseSchema):
    """Base schema for alignment type data."""

    name: str = Field(
        ..., description="Name of the alignment type", min_length=1, max_length=255
    )


class AlignmentTypeCreateRequest(AlignmentTypeBase):
    """Request schema for creating an alignment type."""

    pass


class AlignmentTypeResponse(AlignmentTypeBase, BaseResponse):
    """Response schema for alignment type data."""

    id: int = Field(..., description="Unique identifier for the alignment type")


class AlignmentExecuteRequest(BaseSchema):
    """Request schema to execute alignment type operations."""

    map_findings: bool = Field(
        default=True, description="Whether to run finding mapping"
    )
    mapping_keys: list[str] | None = Field(
        None,
        description="Finding key fields to use when mapFindings is enabled",
        min_length=1,
    )
    store_finding_dependencies: bool = Field(
        default=True,
        description="Whether to store finding dependencies for impact assessment",
    )
    dryrun_commands: bool = Field(
        default=False,
        description="Whether to output the commands that would be executed without actually executing them",
    )


class AlignmentExecuteResponse(BaseResponse):
    """Response schema for alignment type execution."""

    alignment_id: UUID = Field(..., description="Alignment identifier")
    alignment_type: str = Field(..., description="Alignment type name")
    operations: list[str] = Field(
        default_factory=list, description="Operations executed"
    )

    pass
