"""
Optional .env loader for API keys.

Lookup priority (first hit wins):

    1. `$CHNB_ENV_FILE` if set — explicit override path
    2. `<project_root>/.env` — per-project, gitignored
    3. `~/.config/chnb/.env` — per-user, survives project moves

`.env` values OVERRIDE pre-existing shell values by default. Flip with
`CHNB_ENV_OVERRIDE=0` (or pass `override=False` to `load_secrets`) if you'd
rather have the shell win — useful for CI where the runner sets canonical
values via env and the `.env` file is a template.

If `python-dotenv` is not installed, this module silently no-ops; the
runners still work fine if you set the API-key env vars in the shell.

Usage at the top of run.py:

    from util.secrets import require
    require('OPENAI_API_KEY')   # raises a clear error pointing at .env if missing
"""
from __future__ import annotations

import os
from pathlib import Path
from typing import Optional

from util.config import ENV_FILE_ENV, ENV_OVERRIDE_ENV, USER_ENV_FILE


_LOADED = False


def _candidate_paths() -> list[Path]:
    """Return .env paths to try, in priority order."""
    from util.paths import PROJECT_ROOT
    paths: list[Path] = []
    env_override = os.environ.get(ENV_FILE_ENV, '').strip()
    if env_override:
        paths.append(Path(env_override).expanduser())
    paths.append(Path(PROJECT_ROOT) / '.env')
    paths.append(USER_ENV_FILE)
    return paths


def load_secrets(verbose: bool = False, override: Optional[bool] = None) -> list[Path]:
    """Populate `os.environ` from any `.env` files we can find.

    Idempotent — subsequent calls are no-ops unless `verbose=True`.
    Returns the list of paths that were loaded (for debugging).
    """
    global _LOADED
    loaded: list[Path] = []

    if override is None:
        override = os.environ.get(ENV_OVERRIDE_ENV, '1').lower() not in ('0', 'false', 'no')

    try:
        from dotenv import load_dotenv
    except ImportError:
        if verbose:
            print('  python-dotenv not installed; skipping .env lookup. '
                  '`pip install python-dotenv` to enable.')
        return loaded

    # python-dotenv's override=True means later files win, so reverse the
    # priority order to keep CHNB_ENV_FILE > project .env > user .env.
    paths = _candidate_paths()
    if override:
        paths = list(reversed(paths))

    for path in paths:
        if path.exists() and path.is_file():
            load_dotenv(path, override=override)
            loaded.append(path)
            if verbose:
                print(f'  loaded {path}  (override={override})')

    _LOADED = True
    return loaded


def require(*keys: str) -> dict[str, str]:
    """Return {key: value} for each requested env var, raising a clear error
    pointing at `.env` if any are missing.

    Intended for use at the top of run.py to fail fast when the
    user hasn't set their API keys.
    """
    load_secrets()
    missing = [k for k in keys if not os.environ.get(k)]
    if missing:
        raise RuntimeError(
            f'Missing required env vars: {", ".join(missing)}.\n'
            f'Either:\n'
            f'  • export them in the current shell, or\n'
            f'  • add them to one of:\n'
            f'      $CHNB_ENV_FILE  (if set)\n'
            f'      {_candidate_paths()[-2]}\n'
            f'      {_candidate_paths()[-1]}'
        )
    return {k: os.environ[k] for k in keys}
