"""
PyGitWeb configuration: env-driven settings via pydantic-settings, constants, and loadavg.
"""

from __future__ import annotations

import os
from pathlib import Path

from pydantic import Field, model_validator
from pydantic_settings import BaseSettings, SettingsConfigDict

# Actions (most identical to gitweb.perl actions)
ACTIONS: set[str] = {
	"blame",
	"blame_incremental",
	"blame_data",
	"blobdiff",
	"blobpatch",
	"blob",
	"blob_plain",
	"commitdiff",
	"commit",
	"heads",
	"history",
	"log",
	"patch",
	"patches",
	"remotes",
	"rss",
	"atom",
	"search",
	"search_help",
	"shortlog",
	"summary",
	"tag",
	"tags",
	"tree",
	"snapshot",
	"object",
	"opml",
	"project_list",
	"project_index",
}

# Map file extension to highlight.js language
BLOB_LANG: dict[str, str] = {
	"py": "python",
	"js": "javascript",
	"ts": "typescript",
	"jsx": "javascript",
	"tsx": "typescript",
	"html": "html",
	"htm": "html",
	"css": "css",
	"scss": "scss",
	"json": "json",
	"md": "markdown",
	"sh": "bash",
	"bash": "bash",
	"yml": "yaml",
	"yaml": "yaml",
	"xml": "xml",
	"go": "go",
	"rs": "rust",
	"java": "java",
	"c": "c",
	"h": "c",
	"cpp": "cpp",
	"cc": "cpp",
	"cxx": "cpp",
	"sql": "sql",
	"r": "r",
	"rb": "ruby",
	"php": "php",
	"swift": "swift",
	"kt": "kotlin",
	"vue": "xml",
	"toml": "toml",
	"ini": "ini",
	"cfg": "ini",
	"dockerfile": "dockerfile",
}


class Settings(BaseSettings):
	"""
	Runtime settings sourced from PYGITWEB_* env vars (and optionally a .env file).

	The auth provider:
	"None" or unset disables authentication. Otherwise "module.path.ClassName" is imported
	lazily in main.py. Planned providers: Root, SSH, OAuth2, OIDC, Matrix, LDAP.
	"""

	model_config = SettingsConfigDict(
		env_prefix="PYGITWEB_",
		env_file=".env",
		env_file_encoding="utf-8",
		case_sensitive=False,
		validate_assignment=True,
		extra="ignore",
	)

	PROJECTROOT: str = Field(default_factory=lambda: str(Path.home()))
	PROJECTS_LIST: str = ""  # falls back to PROJECTROOT when blank
	PROJECT_MAXDEPTH: int = 1
	SITE_NAME: str = "PyGitWeb"
	EXPORT_OK: str = ""
	LIST_ALL: bool = True
	STRICT_EXPORT: bool = False
	GIT: str = "git"
	MAXLOAD: float | None = None

	AUTH: str | None = None
	ADMIN_USER: str | None = None
	ADMIN_PASSWORD: str | None = None
	SESSION_TIMEOUT: int = 3600 * 24 * 7

	@model_validator(mode="after")
	def _defaults(self) -> Settings:
		if not self.PROJECTS_LIST:
			self.PROJECTS_LIST = self.PROJECTROOT
		if self.AUTH == "None":
			self.AUTH = None
		return self


settings = Settings()


def get_loadavg() -> float:
	"""First element of load average, or 0 if unavailable. Port of get_loadavg."""
	try:
		return os.getloadavg()[0]
	except (OSError, AttributeError):
		pass
	try:
		with open("/proc/loadavg") as f:
			return float(f.read().split()[0])
	except (OSError, ValueError):
		return 0.0


def check_loadavg() -> None:
	"""Raise 503 if load exceeds MAXLOAD."""
	if settings.MAXLOAD is not None and get_loadavg() > settings.MAXLOAD:
		raise RuntimeError("503:The load average on the server is too high")