"""Pydantic models for manifest configuration."""

import os
from pathlib import Path
from typing import Literal

from pydantic import BaseModel, Field, field_validator


def _resolve_int_field(v: int | str) -> int:
    """Resolve an integer field that may contain an env var reference."""
    if isinstance(v, str):
        v = os.path.expandvars(v)
        return int(v)
    return v


class RemoteConfig(BaseModel):
    """Configuration for a remote git forge."""

    name: str
    base_url: str
    branch: str | None = None
    parallelism: int | None = None
    timeout: int | None = None


class ProjectConfig(BaseModel):
    """Configuration for a single project/repository."""

    slug: str  # Set by loader if not provided (derived from path)
    path: Path
    remote: str | None = None
    branch: str | None = None
    status: Literal["active", "archived", "deleted"] = "active"


class CommonConfig(BaseModel):
    """Common/default configuration values."""

    root_path: Path
    branch: str = "main"
    remote: str
    parallelism: int = Field(default=4, ge=1, le=32)
    log_level: str = "info"
    timeout: int = Field(default=300, ge=1)
    ignore_extra: list[str] = Field(default_factory=list)
    normalize_git_url: list[str] = Field(default_factory=list)

    @field_validator("root_path", mode="before")
    @classmethod
    def expand_root_path(cls, v: str | Path) -> Path:
        """Expand ~ and environment variables in root_path."""
        return Path(os.path.expandvars(str(v))).expanduser()

    @field_validator("parallelism", mode="before")
    @classmethod
    def resolve_parallelism(cls, v: int | str) -> int:
        """Resolve env vars in parallelism (e.g. '$REPO_SYNC_PARALLELISM')."""
        return _resolve_int_field(v)

    @field_validator("timeout", mode="before")
    @classmethod
    def resolve_timeout(cls, v: int | str) -> int:
        """Resolve env vars in timeout (e.g. '$REPO_SYNC_TIMEOUT')."""
        return _resolve_int_field(v)


class Manifest(BaseModel):
    """Top-level manifest model."""

    common: CommonConfig
    remotes: list[RemoteConfig] = Field(default_factory=list)
    projects: list[ProjectConfig] = Field(default_factory=list)
