from __future__ import annotations

import os
import pwd
import tempfile
from dataclasses import dataclass
from pathlib import Path


@dataclass(frozen=True)
class AppPaths:
    config_dir: Path
    state_dir: Path
    log_dir: Path
    report_dir: Path
    scenario_file: Path
    app_log_file: Path


def _invoking_user() -> tuple[str, Path]:
    sudo_user = os.environ.get("SUDO_USER")
    if sudo_user:
        user_info = pwd.getpwnam(sudo_user)
        return sudo_user, Path(user_info.pw_dir)

    user = os.environ.get("USER", "root")
    home = Path.home()
    return user, home


def build_paths() -> AppPaths:
    _, user_home = _invoking_user()
    config_home = Path(os.environ.get("XDG_CONFIG_HOME", user_home / ".config"))
    state_home = Path(os.environ.get("XDG_STATE_HOME", user_home / ".local" / "state"))

    config_dir = _select_writable_dir(
        [
            config_home / "securecheck",
            Path.cwd() / ".securecheck-runtime" / "config",
            Path(tempfile.gettempdir()) / "securecheck" / "config",
        ]
    )
    state_dir = _select_writable_dir(
        [
            state_home / "securecheck",
            Path.cwd() / ".securecheck-runtime" / "state",
            Path(tempfile.gettempdir()) / "securecheck" / "state",
        ]
    )

    if os.geteuid() == 0 and _is_path_writable(Path("/var/log")):
        log_dir = Path("/var/log/securecheck")
    else:
        log_dir = _select_writable_dir(
            [
                state_dir / "logs",
                Path.cwd() / ".securecheck-runtime" / "logs",
                Path(tempfile.gettempdir()) / "securecheck" / "logs",
            ]
        )

    report_dir = log_dir / "reports"
    scenario_file = config_dir / "scenarios.json"
    app_log_file = log_dir / "securecheck.log"
    return AppPaths(
        config_dir=config_dir,
        state_dir=state_dir,
        log_dir=log_dir,
        report_dir=report_dir,
        scenario_file=scenario_file,
        app_log_file=app_log_file,
    )


def ensure_app_dirs(paths: AppPaths) -> None:
    for directory in (paths.config_dir, paths.state_dir, paths.log_dir, paths.report_dir):
        directory.mkdir(parents=True, exist_ok=True)


def _is_path_writable(path: Path) -> bool:
    target = path if path.exists() else path.parent
    return os.access(target, os.W_OK)


def _select_writable_dir(candidates: list[Path]) -> Path:
    for candidate in candidates:
        try:
            candidate.mkdir(parents=True, exist_ok=True)
            probe = candidate / ".write-test"
            with probe.open("w", encoding="utf-8") as handle:
                handle.write("ok")
            probe.unlink()
            return candidate
        except OSError:
            continue
    raise OSError("Aucun emplacement inscriptible disponible pour SecureCheck")
