import os

from granian.cli import cli as granian_cli
from pydantic import BaseModel, Field
from pydantic_settings import BaseSettings, SettingsConfigDict


class WorkersSettings(BaseModel):
    per_core: int = Field(1, ge=1)
    max: int | None = Field(None, ge=1)
    exact: int | None = Field(None, ge=1)

    @property
    def count(self) -> int:
        # usage of "or" operator: values here are not allowed to be 0
        base = self.exact or (self.per_core * (os.cpu_count() or 1))
        return min(base, self.max or base)


class BindSettings(BaseModel):
    host: str = "0.0.0.0"
    port: int = 8000


class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        env_prefix="ADVENT22__",
        env_nested_delimiter="__",
    )

    workers: WorkersSettings = WorkersSettings()
    bind: BindSettings = BindSettings()


def start():
    os.environ["ADVENT22__PRODUCTION_MODE"] = "true"

    settings = Settings()
    granian_cli(
        [
            "--host",
            settings.bind.host,
            "--port",
            settings.bind.port,
            "--workers",
            settings.workers.count,
            "--interface",
            "asgi",
            "--loop",
            "uvloop",
            "--process-name",
            "advent22",
            # app
            "advent22_api.app:app",
        ],
        auto_envvar_prefix="GRANIAN",
        standalone_mode=False,
    )
