"""Data root resolution — where the app reads/writes live data (docs, state, config, etc.).

Supports VASTIAN_DATA_ROOT env, CLI override via config/local/data_root.txt,
and defaults to a platform-specific user data directory. Never uses project root
for user data (stops saved_prompts/etc from being created in the repo).
"""

from __future__ import annotations

import os
import re
import sys
from pathlib import Path

# Ensure .env is loaded so VASTIAN_DATA_ROOT is visible to os.environ
try:
    from dotenv import load_dotenv

    load_dotenv()
except ImportError:
    pass


_DATA_ROOT_FILE = "config/local/data_root.txt"

# Markers that identify the Vastian project root (where config/local/data_root.txt lives)
_PROJECT_ROOT_MARKERS = ("pyproject.toml", ".git")


def _find_project_root(start: Path) -> Path:
    """Walk up from start to find project root (pyproject.toml or .git)."""
    current = start.resolve()
    for _ in range(20):  # limit depth
        for marker in _PROJECT_ROOT_MARKERS:
            if (current / marker).exists():
                return current
        parent = current.parent
        if parent == current:
            break
        current = parent
    return start  # fallback to original


def _default_user_data_root() -> Path:
    """Platform-specific default user data directory. Never uses repo/project root."""
    if sys.platform == "win32":
        base = Path(os.environ.get("LOCALAPPDATA", os.path.expanduser("~") + "/AppData/Local"))
    elif sys.platform == "darwin":
        base = Path.home() / "Library" / "Application Support"
    else:
        base = Path(os.environ.get("XDG_DATA_HOME", Path.home() / ".local" / "share"))
    return (base / "vastian").resolve()


def _update_env_data_root(project_root: Path, path: str | None) -> tuple[bool, str]:
    """Update or remove VASTIAN_DATA_ROOT in .env. Returns (success, error_msg)."""
    env_path = project_root / ".env"
    try:
        content = env_path.read_text(encoding="utf-8") if env_path.exists() else ""
        pattern = re.compile(r"^.*VASTIAN_DATA_ROOT=.*\n?", re.MULTILINE)
        if path:
            # Use forward slashes in .env to avoid backslash escaping issues on Windows
            path_safe = str(Path(path).resolve()).replace("\\", "/")
            new_line = f"VASTIAN_DATA_ROOT={path_safe}\n"
            if pattern.search(content):
                content = pattern.sub(new_line, content)
            else:
                suffix = f"\n# Data root — set via: vastian config data-root\n{new_line}"
                content = (content.rstrip() + suffix) if content.strip() else new_line
        else:
            content = pattern.sub("", content)
        env_path.parent.mkdir(parents=True, exist_ok=True)
        env_path.write_text(content, encoding="utf-8")
        return True, ""
    except OSError as e:
        return False, str(e)


def get_data_root(project_root: Path | None = None) -> Path:
    """Return the data root path for docs/, state/, config/, saved_prompts/, workspace/.

    Resolution order:
    1. config/local/data_root.txt (CLI-set override via `vastian config data-root`)
    2. VASTIAN_DATA_ROOT environment variable
    3. Platform default user data dir (e.g. ~/AppData/Local/vastian on Windows)

    Never falls back to project root — prevents saved_prompts, state, docs from
    being created in the repo. Data folder is required for Tauri/desktop app.
    """
    # Use explicit project_root, or find project root from cwd (pyproject.toml/.git)
    # so config/local/data_root.txt is found even when cwd is a subdir or app bundle
    root = project_root.resolve() if project_root is not None else _find_project_root(Path.cwd())
    # CLI override (persisted by vastian config data-root, lives in repo)
    override_file = root / _DATA_ROOT_FILE
    if override_file.exists():
        try:
            path_str = override_file.read_text(encoding="utf-8").strip()
            if path_str:
                p = Path(path_str)
                if p.is_absolute():
                    return p.resolve()
                return (root / p).resolve()
        except OSError:
            pass
    # Env override
    env_path = os.environ.get("VASTIAN_DATA_ROOT", "").strip()
    if env_path:
        p = Path(env_path)
        if p.is_absolute():
            return p.resolve()
        return (root / p).resolve()
    # Platform default — never use project root for user data
    return _default_user_data_root()


def get_config_dir(project_root: Path | None = None) -> Path:
    """Return the config directory. When data root is set, config lives at {data_root}/config/."""
    return get_data_root(project_root) / "config"


def get_saved_prompts_dir(project_root: Path | None = None) -> Path:
    """Return saved_prompts directory (inbox, intake, complete). Lives under data root."""
    return get_data_root(project_root) / "saved_prompts"


def set_data_root(project_root: Path, path: Path | str) -> tuple[bool, str]:
    """Persist the data root path for CLI override.

    Writes to config/local/data_root.txt and .env. Use empty path to clear (revert to default).
    Refuses to set data root to the project/repo (prevents state/, saved_prompts/ in repo).
    Returns (success, error_msg).
    """
    path_str = str(path).strip() if path else ""
    if path_str:
        p = Path(path_str)
        resolved = p.resolve() if p.is_absolute() else (project_root / p).resolve()
        proj_resolved = _find_project_root(project_root).resolve()
        # Refuse: data root must not be project or inside it
        proj_parts = proj_resolved.parts
        res_parts = resolved.parts
        if resolved == proj_resolved or (
            len(res_parts) >= len(proj_parts) and res_parts[: len(proj_parts)] == proj_parts
        ):
            return (
                False,
                f"Cannot set data root to project or inside it ({resolved}). Use a path outside the repo (e.g. Documents/myvastian-user-data).",
            )
    override_file = project_root / _DATA_ROOT_FILE
    try:
        override_file.parent.mkdir(parents=True, exist_ok=True)
        override_file.write_text(path_str, encoding="utf-8")
    except OSError as e:
        return False, str(e)
    ok, err = _update_env_data_root(project_root, path_str if path_str else None)
    if not ok:
        return False, err or "Could not update .env"
    return True, ""


def clear_data_root_override(project_root: Path) -> tuple[bool, str]:
    """Clear the CLI-set data root override (data_root.txt and .env). Returns (success, error_msg)."""
    override_file = project_root / _DATA_ROOT_FILE
    try:
        if override_file.exists():
            override_file.unlink()
        ok, err = _update_env_data_root(project_root, None)
        return (ok, err) if ok else (False, err or "Could not update .env")
    except OSError as e:
        return False, str(e)
