"""Agent-administered secrets setup.

Given a vault's Config, compute the ordered, de-duplicated set of *credential* names
the vault needs — Core's plus each enabled module's ``secrets_required`` (read from that
module's ``module.yml``) — and render how to provision them for whichever backend the
config selects:

  * ``github-actions`` (the laptop tier): exact ``gh secret set`` command lines, one per
    secret, scoped to the repo, with a placeholder value the user replaces.
  * ``dotenv`` (a self-hosted always-on runner): the off-repo ``.env`` path guidance — the
    file is written OUTSIDE the vault checkout, ``chmod 600``, never committed.

Email *addresses* are Config (``owner_digests[].to``, ``team[].email``, ``peers[].agent_email``),
never secrets — so they never appear here. Secrets are referenced by NAME; their VALUES are
read from the environment at runtime. The narrative how-to for each credential lives in the
rendered Core doc ``Agent/SECRETS.md``.

Import-light by design: stdlib + the package's own ``config``/``modules`` modules.
"""
from __future__ import annotations

import os

from . import config as cfgmod, modules as modmod

# A credential we always want present even if a manifest forgot to list it.
_CORE_SECRETS = ["ANTHROPIC_API_KEY"]

# Off-repo secrets env file (dotenv backend). The default is an unobtrusive, durable
# macOS location — hidden under ~/Library, survives, outside any git checkout. Legacy
# paths stay in the search order so existing installs keep working.
DEFAULT_ENV_PATH = "~/Library/Application Support/Alexandria/alexandria.env"
_LEGACY_ENV_PATHS = ["~/Alexandria-secrets/alexandria.env",
                     "~/.config/alexandria/alexandria.env"]


def env_candidates() -> list:
    """Env-file search order, first match wins: the ALEXANDRIA_ENV override, the current
    default location, then legacy paths (for migration)."""
    out = [os.environ.get("ALEXANDRIA_ENV")]
    out += [os.path.expanduser(p) for p in [DEFAULT_ENV_PATH, *_LEGACY_ENV_PATHS]]
    return out


def required_secrets(config: dict, repo_root: str | None = None) -> list:
    """The ordered, de-duplicated credential NAMES this vault needs.

    Union of: Core's ``secrets_required`` + every enabled module's ``secrets_required``
    (from each ``module.yml``) + any names the config pins under ``secrets.required``.
    First-seen order is preserved so Core/runner essentials lead. Defensive: an unknown
    or unreadable module manifest is skipped rather than raising — a half-resolved config
    should still produce a useful list."""
    root = repo_root or modmod.REPO_ROOT
    ordered: list = []

    def add(names):
        for n in names or []:
            n = str(n).strip()
            if n and n not in ordered:
                ordered.append(n)

    add(_CORE_SECRETS)

    enabled = cfgmod.enabled_modules(config)
    ids, _ = modmod.resolve(enabled, root)
    for mid in ids:
        try:
            man = modmod.load_manifest(mid, root)
        except OSError:
            continue
        add(man.get("secrets_required"))

    # Config may pin extra required names (e.g. a per-peer *_TOKEN_SHA256 the user added).
    add((config.get("secrets") or {}).get("required"))
    return ordered


def backend(config: dict) -> str:
    """The provisioning backend: ``github-actions`` or ``dotenv`` (the default)."""
    return (config.get("secrets") or {}).get("backend") or "dotenv"


def gh_secret_commands(config: dict, repo_root: str | None = None,
                       repo: str | None = None) -> list:
    """``gh secret set`` command lines for the ``github-actions`` backend — one per
    required secret, scoped to the repo, with a placeholder the user replaces. Returns a
    list of strings (no trailing newlines) so a caller can print or join them."""
    repo = repo or config.get("repo") or "<owner>/<repo>"
    lines = []
    for name in required_secrets(config, repo_root):
        lines.append(f'gh secret set {name} --repo {repo} --body "<{name}>"')
    return lines


def dotenv_guidance(config: dict, repo_root: str | None = None) -> dict:
    """Off-repo ``.env`` guidance for the ``dotenv`` (self-hosted) backend: the recommended
    path (OUTSIDE the vault checkout), the secrets to put in it, and the safety notes. The
    path is generic — the user picks where, as long as it's not inside the vault."""
    return {
        "path": DEFAULT_ENV_PATH,
        "secrets": required_secrets(config, repo_root),
        "notes": [
            "Easiest: `alexandria secrets --set` prompts for each value (hidden) and writes "
            "this file for you — no editor, correct permissions.",
            "It lives OUTSIDE the vault (never committed), chmod 600, hidden under ~/Library.",
            "One KEY=VALUE per line; the wrappers load it into the environment at runtime.",
        ],
    }


def walkthrough(config: dict, repo_root: str | None = None) -> dict:
    """The structured walkthrough payload the CLI renders: the backend, the ordered secret
    names, and the per-backend provisioning steps. A single source the CLI prints from."""
    bk = backend(config)
    out = {
        "backend": bk,
        "secrets": required_secrets(config, repo_root),
        "addresses_note": (
            "Recipient addresses are Config, not secrets — they live in config.json / "
            "Roster.md, never in the secret store."
        ),
    }
    if bk == "github-actions":
        out["gh_commands"] = gh_secret_commands(config, repo_root)
    else:
        out["dotenv"] = dotenv_guidance(config, repo_root)
    return out


def render_text(config: dict, repo_root: str | None = None) -> str:
    """A plain-text rendering of the walkthrough, for the ``alexandria secrets`` CLI."""
    wt = walkthrough(config, repo_root)
    lines = [
        "Secrets walkthrough",
        "===================",
        "",
        f"Backend: {wt['backend']}",
        "",
        "Credentials this vault needs (names only — values are read from the environment):",
    ]
    for name in wt["secrets"]:
        lines.append(f"  - {name}")
    lines.append("")
    lines.append(wt["addresses_note"])
    lines.append("")
    if wt["backend"] == "github-actions":
        lines.append("Provision as GitHub Actions repository secrets (replace each <PLACEHOLDER>):")
        lines.append("")
        for cmd in wt["gh_commands"]:
            lines.append(f"  {cmd}")
    else:
        dv = wt["dotenv"]
        lines.append("Enter the values with the guided setter (no editor needed):")
        lines.append("")
        lines.append("  alexandria secrets --set --vault <vault>")
        lines.append(f"  → writes {dv['path']}")
        lines.append("")
        lines.append("Secrets it will ask for:")
        for name in dv["secrets"]:
            lines.append(f"  - {name}")
        lines.append("")
        for note in dv["notes"]:
            lines.append(f"  * {note}")
    lines.append("")
    lines.append("Full how-to for each credential: Agent/SECRETS.md")
    return "\n".join(lines)
