"""
Configuration management for Nia Local Sync CLI.

Handles:
- Local config storage (~/.nia-sync/config.json)
- Fetching source configuration from cloud API
"""
import os
import json
from pathlib import Path
from typing import Any
# Configuration paths
NIA_SYNC_DIR = Path.home() / ".nia-sync"
CONFIG_FILE = NIA_SYNC_DIR / "config.json"

# API configuration
DEFAULT_API_BASE_URL = "https://apigcp.trynia.ai"

# Default directories to search for folders (no config needed)
DEFAULT_WATCH_DIRS = [
    "~/Documents",
    "~/Desktop",
    "~/Projects",
    "~/Developer",
    "~/Code",
    "~/dev",
    "~/repos",
    "~/Downloads",
    "~/src",
    "~/work",
    "~/workspace",
    "~/github",
]


def get_api_base_url() -> str:
    """Get API base URL, preferring env var over config."""
    env_url = os.getenv("NIA_API_URL")
    if env_url:
        return env_url
    config = load_config()
    return config.get("api_url", DEFAULT_API_BASE_URL)


def get_watch_dirs() -> list[str]:
    """Get directories to search for folders. Uses defaults + any custom ones."""
    config = load_config()
    custom = config.get("watch_dirs", [])
    # Combine defaults + custom, dedupe
    all_dirs = DEFAULT_WATCH_DIRS + custom
    return list(dict.fromkeys(all_dirs))


def set_watch_dirs(dirs: list[str]) -> None:
    normalized = [os.path.abspath(os.path.expanduser(d)) for d in dirs if d]
    save_config({"watch_dirs": list(dict.fromkeys(normalized))})


def add_watch_dir(path: str) -> bool:
    if not path:
        return False
    expanded = os.path.abspath(os.path.expanduser(path))
    config = load_config()
    custom = config.get("watch_dirs", [])
    if expanded in custom:
        return False
    custom.append(expanded)
    save_config({"watch_dirs": custom})
    return True


def remove_watch_dir(path: str) -> bool:
    if not path:
        return False
    expanded = os.path.abspath(os.path.expanduser(path))
    config = load_config()
    custom = config.get("watch_dirs", [])
    if expanded not in custom:
        return False
    custom = [d for d in custom if d != expanded]
    save_config({"watch_dirs": custom})
    return True


def find_folder_path(folder_name: str, max_depth: int = 3) -> str | None:
    """
    Search watch directories recursively for a folder with the given name.
    Returns the full path if found, None otherwise.

    Searches up to max_depth levels deep to avoid scanning entire filesystem.
    """
    def search_dir(base: str, depth: int) -> str | None:
        if depth > max_depth:
            return None

        try:
            for entry in os.scandir(base):
                if not entry.is_dir():
                    continue
                # Skip hidden directories and common large dirs
                if entry.name.startswith('.') or entry.name in ('node_modules', 'venv', '__pycache__', 'build', 'dist'):
                    continue

                if entry.name == folder_name:
                    return entry.path

                # Recurse into subdirectory
                if depth < max_depth:
                    found = search_dir(entry.path, depth + 1)
                    if found:
                        return found
        except PermissionError:
            pass

        return None

    for watch_dir in get_watch_dirs():
        expanded = os.path.expanduser(watch_dir)
        if not os.path.isdir(expanded):
            continue

        # Check direct child first (fast path)
        candidate = os.path.join(expanded, folder_name)
        if os.path.exists(candidate):
            return candidate

        # Search recursively
        found = search_dir(expanded, 1)
        if found:
            return found

    return None


def ensure_config_dir():
    """Ensure the config directory exists."""
    NIA_SYNC_DIR.mkdir(parents=True, exist_ok=True)


def load_config() -> dict[str, Any]:
    """Load configuration from disk."""
    if not CONFIG_FILE.exists():
        return {}

    try:
        with open(CONFIG_FILE, "r") as f:
            return json.load(f)
    except (json.JSONDecodeError, IOError):
        return {}


def save_config(config: dict[str, Any]):
    """Save configuration to disk."""
    ensure_config_dir()

    # Merge with existing config
    existing = load_config()
    existing.update(config)

    with open(CONFIG_FILE, "w") as f:
        json.dump(existing, f, indent=2)

    # Secure the file (readable only by owner)
    os.chmod(CONFIG_FILE, 0o600)


def clear_config():
    """Clear all stored configuration."""
    if CONFIG_FILE.exists():
        CONFIG_FILE.unlink()


def get_api_key() -> str | None:
    """Get the stored API key. Checks NIA_API_KEY env var first, then config file."""
    env_key = os.getenv("NIA_API_KEY")
    if env_key:
        return env_key
    config = load_config()
    return config.get("api_key")


def get_config_value(key: str) -> Any:
    config = load_config()
    if not key:
        return config
    return config.get(key)


def set_config_value(key: str, value: Any) -> None:
    if not key:
        return
    save_config({key: value})


def get_ignore_patterns() -> dict[str, list[str]]:
    config = load_config()
    return {
        "dirs": list(config.get("ignore_dirs", [])),
        "files": list(config.get("ignore_files", [])),
        "extensions": list(config.get("ignore_extensions", [])),
        "path_patterns": list(config.get("ignore_path_patterns", [])),
    }


def add_ignore_pattern(kind: str, value: str) -> bool:
    if not kind or not value:
        return False
    config = load_config()
    key_map = {
        "dir": "ignore_dirs",
        "file": "ignore_files",
        "ext": "ignore_extensions",
        "path": "ignore_path_patterns",
    }
    key = key_map.get(kind)
    if not key:
        return False
    current = list(config.get(key, []))
    normalized = value.strip()
    if kind == "ext" and not normalized.startswith("."):
        normalized = f".{normalized}"
    if normalized in current:
        return False
    current.append(normalized)
    save_config({key: current})
    return True


def remove_ignore_pattern(kind: str, value: str) -> bool:
    if not kind or not value:
        return False
    config = load_config()
    key_map = {
        "dir": "ignore_dirs",
        "file": "ignore_files",
        "ext": "ignore_extensions",
        "path": "ignore_path_patterns",
    }
    key = key_map.get(kind)
    if not key:
        return False
    current = list(config.get(key, []))
    normalized = value.strip()
    if kind == "ext" and not normalized.startswith("."):
        normalized = f".{normalized}"
    if normalized not in current:
        return False
    current = [item for item in current if item != normalized]
    save_config({key: current})
    return True


def update_source_cursor(local_folder_id: str, cursor: dict[str, Any]) -> bool:
    """
    Update the sync cursor for a source after successful sync.

    This is called by the sync engine after pushing data to the backend.
    The backend updates the cursor in the database.
    """
    # Note: Cursor is updated by the /daemon/sync endpoint, not a separate call
    # This function is here for potential future use
    return True
