from __future__ import annotations

import os
from dataclasses import dataclass

from omni_manager.settings import (
    ConfigurationError,
    _env_bool,
    _env_float,
    _env_int,
    validate_local_url,
)


@dataclass(slots=True)
class MediaSettings:
    host: str = "127.0.0.1"
    port: int = 8111
    allow_container_bind: bool = False
    allow_container_endpoints: bool = False
    manager_url: str = "http://127.0.0.1:8110"
    video_endpoint: str | None = None
    image_endpoint: str | None = None
    auto_start: bool = False
    max_active_jobs: int = 16
    max_records: int = 128
    max_events_per_job: int = 256
    max_subscribers: int = 32
    max_artifacts: int = 16
    max_options_bytes: int = 16 * 1024
    max_request_bytes: int = 64 * 1024
    max_response_bytes: int = 256 * 1024
    max_sse_event_bytes: int = 64 * 1024
    max_downstream_events: int = 1024
    connect_timeout_s: float = 0.75
    request_timeout_s: float = 30.0
    stream_timeout_s: float = 900.0
    job_timeout_s: float = 900.0
    subscriber_heartbeat_s: float = 15.0

    @classmethod
    def from_env(cls) -> "MediaSettings":
        return cls(
            host=os.getenv("OMNI_MEDIA_HOST", "127.0.0.1"),
            port=_env_int("OMNI_MEDIA_PORT", 8111),
            allow_container_bind=_env_bool("OMNI_MEDIA_ALLOW_CONTAINER_BIND"),
            allow_container_endpoints=_env_bool("OMNI_MEDIA_ALLOW_CONTAINER_ENDPOINTS"),
            manager_url=os.getenv("OMNI_MANAGER_URL", "http://127.0.0.1:8110"),
            video_endpoint=os.getenv("H3_CONTROLLER_URL") or None,
            image_endpoint=os.getenv("HUNYUAN_URL") or None,
            auto_start=_env_bool("OMNI_MEDIA_AUTO_START"),
            max_active_jobs=_env_int("OMNI_MEDIA_MAX_ACTIVE_JOBS", 16),
            max_records=_env_int("OMNI_MEDIA_MAX_RECORDS", 128),
            max_events_per_job=_env_int("OMNI_MEDIA_MAX_EVENTS_PER_JOB", 256),
            max_subscribers=_env_int("OMNI_MEDIA_MAX_SUBSCRIBERS", 32),
            max_artifacts=_env_int("OMNI_MEDIA_MAX_ARTIFACTS", 16),
            max_options_bytes=_env_int("OMNI_MEDIA_MAX_OPTIONS_BYTES", 16 * 1024),
            max_request_bytes=_env_int("OMNI_MEDIA_MAX_REQUEST_BYTES", 64 * 1024),
            max_response_bytes=_env_int("OMNI_MEDIA_MAX_RESPONSE_BYTES", 256 * 1024),
            max_sse_event_bytes=_env_int("OMNI_MEDIA_MAX_SSE_EVENT_BYTES", 64 * 1024),
            max_downstream_events=_env_int("OMNI_MEDIA_MAX_DOWNSTREAM_EVENTS", 1024),
            connect_timeout_s=_env_float("OMNI_MEDIA_CONNECT_TIMEOUT_S", 0.75),
            request_timeout_s=_env_float("OMNI_MEDIA_REQUEST_TIMEOUT_S", 30),
            stream_timeout_s=_env_float("OMNI_MEDIA_STREAM_TIMEOUT_S", 900),
            job_timeout_s=_env_float("OMNI_MEDIA_JOB_TIMEOUT_S", 900),
            subscriber_heartbeat_s=_env_float("OMNI_MEDIA_SUBSCRIBER_HEARTBEAT_S", 15),
        ).validated()

    def validated(self) -> "MediaSettings":
        if self.host not in {"127.0.0.1", "localhost", "::1"}:
            if self.host not in {"0.0.0.0", "::"} or not self.allow_container_bind:
                raise ConfigurationError(
                    "OMNI_MEDIA_HOST must be loopback; a wildcard container bind "
                    "requires OMNI_MEDIA_ALLOW_CONTAINER_BIND=1"
                )
        if not 1 <= self.port <= 65_535:
            raise ConfigurationError("OMNI_MEDIA_PORT must be a valid port")
        for name in (
            "max_active_jobs", "max_records", "max_events_per_job", "max_subscribers",
            "max_artifacts", "max_options_bytes", "max_request_bytes", "max_response_bytes",
            "max_sse_event_bytes", "max_downstream_events",
        ):
            if getattr(self, name) <= 0:
                raise ConfigurationError(f"{name} must be positive")
        if self.max_records < self.max_active_jobs:
            raise ConfigurationError("max_records cannot be smaller than max_active_jobs")
        if min(
            self.connect_timeout_s,
            self.request_timeout_s,
            self.stream_timeout_s,
            self.job_timeout_s,
            self.subscriber_heartbeat_s,
        ) <= 0:
            raise ConfigurationError("media timeouts must be positive")
        if self.auto_start:
            raise ConfigurationError(
                "OMNI_MEDIA_AUTO_START is intentionally unsupported; use the manager's "
                "explicit fixed launch hooks instead"
            )
        self.manager_url = validate_local_url(
            self.manager_url,
            allow_container=self.allow_container_endpoints,
            name="OMNI_MANAGER_URL",
        )
        for field_name in ("video_endpoint", "image_endpoint"):
            value = getattr(self, field_name)
            if value:
                setattr(
                    self,
                    field_name,
                    validate_local_url(
                        value,
                        allow_container=self.allow_container_endpoints,
                        name=field_name,
                    ),
                )
        return self

    def endpoint(self, kind: str) -> str | None:
        return self.video_endpoint if kind == "video" else self.image_endpoint
