from pydantic import Field, model_validator

from ..base import FrigateBaseModel

__all__ = ["DetectConfig", "StationaryConfig", "StationaryMaxFramesConfig"]


class StationaryMaxFramesConfig(FrigateBaseModel):
    default: int | None = Field(
        default=None,
        title="Default max frames",
        description="Default maximum frames to track a stationary object before stopping.",
        ge=1,
    )
    objects: dict[str, int] = Field(
        default_factory=dict,
        title="Object max frames",
        description="Per-object overrides for maximum frames to track stationary objects.",
    )


class StationaryConfig(FrigateBaseModel):
    interval: int | None = Field(
        default=None,
        title="Stationary interval",
        description="How often (in frames) to run a detection check to confirm a stationary object.",
        gt=0,
    )
    threshold: int | None = Field(
        default=None,
        title="Stationary threshold",
        description="Number of frames with no position change required to mark an object as stationary.",
        ge=1,
    )
    max_frames: StationaryMaxFramesConfig = Field(
        default_factory=StationaryMaxFramesConfig,
        title="Max frames",
        description="Limits how long stationary objects are tracked before being discarded.",
    )
    classifier: bool = Field(
        default=True,
        title="Enable visual classifier",
        description="Use a visual classifier to detect truly stationary objects even when bounding boxes jitter.",
    )


class DetectConfig(FrigateBaseModel):
    enabled: bool = Field(
        default=False,
        title="Enable object detection",
        description="Enable or disable object detection for all cameras; can be overridden per-camera.",
    )
    model: str | None = Field(
        default=None,
        title="Detection model name",
        description="Name of the model (key under `models`) used by this camera. Defaults to the only defined model, or the model named 'default'.",
    )
    height: int | None = Field(
        default=None,
        title="Detect height",
        description="Height (pixels) of frames used for the detect stream; leave empty to use the native stream resolution.",
    )
    width: int | None = Field(
        default=None,
        title="Detect width",
        description="Width (pixels) of frames used for the detect stream; leave empty to use the native stream resolution.",
    )
    fps: int = Field(
        default=5,
        title="Detect FPS",
        description="Desired frames per second to run detection on; lower values reduce CPU usage (recommended value is 5, only set higher - at most 10 - if tracking extremely fast moving objects).",
    )
    min_initialized: int | None = Field(
        default=None,
        title="Minimum initialization frames",
        description="Number of consecutive detection hits required before creating a tracked object. Increase to reduce false initializations. Default value is fps divided by 2.",
        ge=2,
    )
    max_disappeared: int | None = Field(
        default=None,
        title="Maximum disappeared frames",
        description="Number of frames without a detection before a tracked object is considered gone.",
    )
    stationary: StationaryConfig = Field(
        default_factory=StationaryConfig,
        title="Stationary objects config",
        description="Settings to detect and manage objects that remain stationary for a period of time.",
    )
    annotation_offset: int = Field(
        default=0,
        title="Annotation offset",
        description="Milliseconds to shift detect annotations to better align timeline bounding boxes with recordings; can be positive or negative.",
    )

    @model_validator(mode="after")
    def validate_dimensions(self) -> "DetectConfig":
        if (self.width is None) != (self.height is None):
            raise ValueError(
                "detect -> both width and height must be specified together, or both omitted"
            )
        return self
