"""
Project Root Discovery and Derived Path Constants.

Dynamically locates the project root by searching for anchor files
(.git, requirements.txt) and derives all core directory paths from it.

Attributes:
    PROJECT_ROOT: Dynamically resolved absolute path to the project root.
    DATASET_DIR: Absolute path to the raw datasets directory.
    OUTPUTS_ROOT: Default root directory for all experiment results.
    MLRUNS_DB: SQLite database path for MLflow experiment tracking.
    STATIC_DIRS: list of directories that must exist at startup.
"""

from __future__ import annotations

import os
from pathlib import Path
from typing import Final


def get_project_root() -> Path:
    """
    Dynamically locate the project root by searching for anchor files.

    Traverses upward from current file's directory until finding a marker
    file (.git or requirements.txt). Supports Docker environments via
    IN_DOCKER environment variable override.

    Returns:
        Resolved absolute Path to the project root directory.

    Note:

        - IN_DOCKER=1 or IN_DOCKER=TRUE returns /app
        - Falls back to fixed parent traversal if no markers found
    """
    # Environment override for Docker setups
    if str(os.getenv("IN_DOCKER")).upper() in ("1", "TRUE"):
        return Path("/app").resolve()

    # Start from the directory of this file
    current_path = Path(__file__).resolve().parent

    # Look for markers that define the project root
    # Note: .git is most reliable; README.md alone can exist in subdirectories
    root_markers = {".git", "requirements.txt"}

    for parent in [current_path] + list(current_path.parents):
        if any((parent / marker).exists() for marker in root_markers):
            return parent

    # Fallback if no markers are found
    try:
        if len(current_path.parents) >= 3:
            return current_path.parents[2]
    except IndexError:  # pragma: no cover
        pass

    # Final fallback
    return current_path.parent.parent  # pragma: no cover


# Central Filesystem Authority
PROJECT_ROOT: Final[Path] = get_project_root().resolve()

# STATIC DIRECTORIES
# Input: Where raw datasets are stored
DATASET_DIR: Final[Path] = (PROJECT_ROOT / "dataset").resolve()

# Output: Default root directory for all experiment results
OUTPUTS_ROOT: Final[Path] = (PROJECT_ROOT / "outputs").resolve()

# Tracking: SQLite database for MLflow experiment tracking
MLRUNS_DB: Final[Path] = (PROJECT_ROOT / "mlruns.db").resolve()

# Directories that must exist at startup
STATIC_DIRS: Final[list[Path]] = [DATASET_DIR, OUTPUTS_ROOT]


# INITIAL SETUP
def setup_static_directories() -> None:
    """
    Ensure core project directories exist at startup.

    Creates DATASET_DIR and OUTPUTS_ROOT if they do not exist, preventing
    runtime errors during data fetching or artifact creation. Uses
    mkdir(parents=True, exist_ok=True) for idempotent operation.
    """
    for directory in STATIC_DIRS:
        directory.mkdir(parents=True, exist_ok=True)
