"""Command-related schemas."""

import re
from typing import Any
from uuid import UUID
from ..model import Field, field_validator
from ..enums import CommandGroupStatus, CommandStatus, CommandType
from .common import BaseResponse, BaseSchema, BaseEventCreateRequest, BaseEventResponse

_CAMEL_CASE_RE = re.compile(r"^[a-z][a-zA-Z0-9]*$")


def _validate_camel_case_keys(value: dict[str, Any]) -> dict[str, Any]:
    """Validate that all top-level keys of a dict are camelCase."""
    invalid_keys = [k for k in value if not _CAMEL_CASE_RE.match(k)]
    if invalid_keys:
        raise ValueError(
            f"command_data keys must be camelCase (e.g. 'itemTypeId'). "
            f"Invalid keys: {invalid_keys}"
        )
    return value


class CommandGroupCreateRequest(BaseSchema):
    """Request schema for creating a command group."""

    bucket_id: UUID = Field(..., description="ID of the associated bucket")
    name: str = Field(..., description="Name of the command group")
    description: str | None = Field(
        None, description="Description of the command group"
    )


class CommandGroupUpdateRequest(BaseSchema):
    """Request schema for updating a command group."""

    name: str | None = Field(None, description="New name of the command group")
    description: str | None = Field(
        None, description="New description of the command group"
    )
    ordinal: int | None = Field(None, description="New order within the bucket", gt=0)


class CommandGroupResponse(BaseResponse):
    """Response schema for command group data."""

    id: UUID = Field(..., description="Unique identifier for the command group")
    bucket_id: UUID = Field(..., description="ID of the associated bucket")
    name: str = Field(..., description="Name of the command group")
    description: str | None = Field(
        None, description="Description of the command group"
    )
    ordinal: int = Field(..., description="Order within the bucket")
    task_id: UUID | None = Field(None, description="ID of the associated task")
    status: CommandGroupStatus = Field(..., description="Status of the command group")
    commands_count: int | None = Field(
        None, description="Number of commands in the group"
    )


class CommandGroupStatusUpdateRequest(BaseSchema):
    """Request schema for updating command group status."""

    status: CommandGroupStatus = Field(
        ..., description="New status for the command group"
    )


class CommandCreateRequest(BaseSchema):
    """Request schema for creating a command."""

    command_type: CommandType = Field(..., description="Type of command")
    command_data: dict[str, Any] = Field(..., description="Command data payload")
    description: str | None = Field(None, description="Optional command description")

    @field_validator("command_data")
    @classmethod
    def validate_command_data_keys(cls, v: dict[str, Any]) -> dict[str, Any]:
        return _validate_camel_case_keys(v)


class UpdateCommandRequest(BaseSchema):
    """Request schema for updating a command."""

    command_group_id: UUID | None = Field(
        None, description="ID of the associated command group"
    )
    command_type: CommandType | None = Field(None, description="Type of command")
    command_data: dict[str, Any] | None = Field(
        None, description="Command data payload"
    )
    description: str | None = Field(None, description="Optional command description")
    command_status: CommandStatus | None = Field(
        None, description="Status of the command"
    )
    ordinal: int | None = Field(
        None, description="Order within the command group", gt=0
    )

    @field_validator("command_data")
    @classmethod
    def validate_command_data_keys(
        cls, v: dict[str, Any] | None
    ) -> dict[str, Any] | None:
        if v is None:
            return v
        return _validate_camel_case_keys(v)


class PushCommandGroupRequest(BaseSchema):
    """Request schema for pushing a command group to a task."""

    crRef: str = Field(..., description="Change Request Reference")
    message: str = Field(..., description="Descriptive message for the task")
    tags: list[str] = Field(
        default_factory=list, description="Tags associated with the task"
    )


class CommandResponse(BaseResponse):
    """Response schema for command data."""

    id: UUID = Field(..., description="Unique identifier for the command")
    command_group_id: UUID = Field(
        ..., description="ID of the associated command group"
    )
    description: str | None = Field(None, description="Command description")
    ordinal: int = Field(..., description="Order within the command group")
    command_type: CommandType = Field(..., description="Type of command")
    command_data: dict[str, Any] = Field(..., description="Command data payload")
    command_status: CommandStatus = Field(..., description="Status of the command")
    # created_by: UUID | None = Field(..., description="User UID who created the command")
    # created_at: str = Field(..., description="Creation timestamp")
    # updated_by: UUID | None = Field(
    #     None, description="User UID who last updated the command"
    # )
    # updated_at: str | None = Field(None, description="Last update timestamp")


class CommandGroupWithCommandsResponse(CommandGroupResponse):
    """Extended response schema including commands in the group."""

    commands: list[CommandResponse] = Field(
        default_factory=list, description="Commands in this group"
    )


# Command-Findings mapping schemas
class CommandFindingsMapCreateRequest(BaseSchema):
    """Request schema for creating a command-findings mapping."""

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


class UpdateCommandFindingsMappingRequest(BaseSchema):
    """Request schema for updating command-findings mappings for a command."""

    finding_ids: list[UUID] = Field(
        ..., description="List of finding IDs to associate with the command"
    )


class CommandFindingsMapResponse(BaseResponse):
    """Response schema for command-findings mapping data."""

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


# Command event schemas
class CommandGroupEventCreateRequest(BaseEventCreateRequest):
    """Request schema for creating a command group event."""

    pass


class CommandEventCreateRequest(BaseEventCreateRequest):
    """Request schema for creating a command event."""

    pass


class CommandEventResponse(BaseEventResponse):
    """Response schema for command event data."""

    command_id: UUID = Field(..., description="ID of the associated command")


class CommandGroupEventResponse(BaseEventResponse):
    """Response schema for command group event data."""

    command_group_id: UUID = Field(
        ..., description="ID of the associated command group"
    )
