from dataclasses import dataclass, field
from os import getenv
from pathlib import Path
from typing import Any

from csirtmu.core.dataclass_config_loader import load_dataclass_config

BASE_DIR = Path(__file__).parent.parent.parent
ENV_PREFIX = "KEYCLOAK_LOADER"


@dataclass
class User:
    username: str
    password: str
    first_name: str
    last_name: str
    email: str
    authorized: bool


@dataclass
class Claim:
    name: str
    capability: dict[Any, Any] | list[Any] | str


@dataclass
class Scope:
    name: str
    claims: list[Claim] = field(default_factory=list[Claim])
    default: bool = False


@dataclass
class Client:
    name: str
    secret: str
    redirect_uris: list[str]
    post_logout_redirect_uris: list[str]
    web_origins: list[str]
    add_default_scopes: list[str]
    add_optional_scopes: list[str]
    exchange_target: bool
    include_audience_mapper: bool = False
    realm_role_mapping_scope: bool = False


@dataclass
class Role:
    name: str
    description: str | None


@dataclass
class Group:
    name: str
    usernames: list[str]
    rolenames: list[str]


@dataclass
class Realm:
    name: str
    url: str
    default: bool | None
    clients: list[Client]
    users: list[User]
    role_mapping_scope: str | None = None
    default_kid: str | None = None
    scopes: list[Scope] = field(default_factory=list[Scope])
    groups: list[Group] = field(default_factory=list[Group])
    roles: list[Role] = field(default_factory=list[Role])


@dataclass
class Keycloak:
    base_url: str
    master_user: str
    master_password: str
    public_url: str
    oidc_provider_header_name: str
    access_token_header_name: str
    access_token_prefix: str
    realms: list[Realm]


@dataclass
class Config:
    debug: bool
    legacy: bool
    keycloak: Keycloak


class AppConfig:
    _config: Config | None = None

    @classmethod
    def get(cls, config_path: Path | None = None) -> Config:
        if cls._config is None:
            if config_path is None:  # pragma: no cover
                config_path = Path(getenv(f"{ENV_PREFIX}_CONFIG_PATH", (BASE_DIR / "config/config.yaml").resolve()))
            cls._config = load_dataclass_config(config_path, Config, ENV_PREFIX)
        return cls._config
