"""End-to-end clean-install integration tests for `agnes init`."""

import json
import os
import subprocess
import sys
from pathlib import Path


AGNES = [sys.executable, "-m", "cli.main"]


def _isolated_env(tmp_path: Path) -> dict:
    """Env with `AGNES_CONFIG_DIR` pointing into tmp_path.

    `cli.config.get_token()` reads `~/.config/agnes/token.json` first and
    only falls back to `AGNES_TOKEN`. Without this isolation a stale token
    on the developer's machine would override the test_pat passed via
    `--token`. Same shape as Task 20's `zero_grants_workspace` fixture.
    """
    env = os.environ.copy()
    config_dir = tmp_path / "agnes-config"
    config_dir.mkdir(parents=True, exist_ok=True)
    env["AGNES_CONFIG_DIR"] = str(config_dir)
    return env


def assert_no_dead_dirs(workspace: Path):
    """Lazy-mkdir contract: forbidden dirs absent; conditionally-empty dirs only when populated."""
    forbidden_unconditional = ["data/parquet", "data/duckdb", "data/metadata",
                               "user/artifacts", ".agnes"]
    for d in forbidden_unconditional:
        assert not (workspace / d).exists(), f"forbidden dir created: {d}"
    for d in [".claude/rules", "server/parquet", "user/sessions", "user/snapshots"]:
        path = workspace / d
        if path.exists():
            assert any(path.iterdir()), f"{d} exists but is empty"


def test_clean_install_minimal_grants(fastapi_test_server, tmp_path, test_pat):
    """`agnes init` with grants → CLAUDE.md, AGNES_WORKSPACE.md, hooks, parquets, DuckDB."""
    workspace = tmp_path / "ws"
    workspace.mkdir()
    result = subprocess.run(AGNES + [
        "init",
        "--server-url", fastapi_test_server.url,
        "--token", test_pat,
        "--workspace", str(workspace),
    ], env=_isolated_env(tmp_path), capture_output=True, text=True)
    assert result.returncode == 0, f"init failed: {result.stderr}"

    # Required files
    for must in ["CLAUDE.md", "AGNES_WORKSPACE.md",
                 ".claude/settings.json", ".claude/CLAUDE.local.md",
                 "user/duckdb/analytics.duckdb"]:
        assert (workspace / must).exists(), f"missing: {must}"

    # Grants → 2 parquets exist (local + materialized; remote is skipped per query_mode)
    parquets = list((workspace / "server" / "parquet").glob("*.parquet"))
    assert len(parquets) >= 1, f"expected >=1 parquet, got {len(parquets)}: {parquets}"

    # No dead dirs
    assert_no_dead_dirs(workspace)

    # Hooks installed
    settings = json.loads((workspace / ".claude" / "settings.json").read_text())
    assert any("agnes pull" in h["hooks"][0]["command"]
               for h in settings.get("hooks", {}).get("SessionStart", []))
    assert any("agnes push" in h["hooks"][0]["command"]
               for h in settings.get("hooks", {}).get("SessionEnd", []))

    # CLAUDE.md was fetched from /api/welcome (not from local template)
    claude_md = (workspace / "CLAUDE.md").read_text()
    assert "agnes pull" in claude_md
    assert "da sync" not in claude_md  # post-rewrite content

    # AGNES_WORKSPACE.md content
    workspace_md = (workspace / "AGNES_WORKSPACE.md").read_text()
    assert test_pat not in workspace_md, "PAT must not leak into AGNES_WORKSPACE.md"
    for placeholder in ["{created_at}", "{server_url}", "{workspace_path}"]:
        assert placeholder not in workspace_md, f"placeholder leaked: {placeholder}"
    assert fastapi_test_server.url in workspace_md
    assert str(workspace) in workspace_md
    assert "agnes pull" in workspace_md  # cheat sheet uses new verb


def test_clean_install_zero_grants(fastapi_test_server, tmp_path, test_pat_no_grants):
    """Zero grants → minimal workspace; no parquets, no rules, no dead dirs."""
    workspace = tmp_path / "ws"
    workspace.mkdir()
    result = subprocess.run(AGNES + [
        "init",
        "--server-url", fastapi_test_server.url,
        "--token", test_pat_no_grants,
        "--workspace", str(workspace),
    ], env=_isolated_env(tmp_path), capture_output=True, text=True)
    assert result.returncode == 0, f"init failed: {result.stderr}"

    must_exist = {"CLAUDE.md", "AGNES_WORKSPACE.md",
                  ".claude/settings.json", ".claude/CLAUDE.local.md",
                  "user/duckdb/analytics.duckdb"}
    must_not_exist = {".claude/rules", "server/parquet", "data/parquet",
                      "data/duckdb", "data/metadata", "user/artifacts",
                      "user/sessions", "user/snapshots", ".agnes"}
    for p in must_exist:
        assert (workspace / p).exists(), f"missing: {p}"
    for p in must_not_exist:
        assert not (workspace / p).exists(), f"unexpected: {p}"
    assert_no_dead_dirs(workspace)


def test_init_force_preserves_local_md(fastapi_test_server, tmp_path, test_pat):
    """`agnes init --force` regenerates CLAUDE.md but never touches CLAUDE.local.md."""
    workspace = tmp_path / "ws"
    workspace.mkdir()
    env = _isolated_env(tmp_path)
    result1 = subprocess.run(AGNES + ["init",
                                      "--server-url", fastapi_test_server.url,
                                      "--token", test_pat, "--workspace", str(workspace)],
                             env=env, capture_output=True, text=True)
    assert result1.returncode == 0, f"first init failed: {result1.stderr}"
    (workspace / ".claude" / "CLAUDE.local.md").write_text("# my private notes\n")

    result2 = subprocess.run(AGNES + ["init",
                                      "--server-url", fastapi_test_server.url,
                                      "--token", test_pat, "--workspace", str(workspace),
                                      "--force"],
                             env=env, capture_output=True, text=True)
    assert result2.returncode == 0, f"force init failed: {result2.stderr}"
    assert "my private notes" in (workspace / ".claude" / "CLAUDE.local.md").read_text()


def test_readers_in_pre_init_dir(tmp_path):
    """Reader commands in a folder that never had `agnes init`. Friendly hints, no tracebacks."""
    env = _isolated_env(tmp_path)
    for cmd in [AGNES + ["query", "SELECT 1"],
                AGNES + ["snapshot", "create", "x", "--as", "y", "--estimate"],
                AGNES + ["explore", "x"],
                AGNES + ["snapshot", "list"]]:
        result = subprocess.run(cmd, cwd=tmp_path, env=env,
                                capture_output=True, text=True, timeout=15)
        assert "Traceback" not in result.stderr, f"{cmd} threw: {result.stderr}"
