"""Init-wizard tests: idempotent setup, credential hygiene, no prompts
without a TTY. All prompts and the browser installer are injected."""

from __future__ import annotations

import os

from bggpipe.config import Config
from bggpipe.init_wizard import run_init


def _clear_env(monkeypatch):
    for key in ("ANTHROPIC_API_KEY", "BGG_USERNAME", "BGG_PASSWORD", "BGG_API_TOKEN"):
        monkeypatch.delenv(key, raising=False)


def _run(tmp_path, *, interactive=True, answers=None, confirm=False, installer=None):
    given = dict(answers or {})

    def prompt(label: str) -> str:
        for key in list(given):
            if key in label:
                return given.pop(key)
        return ""

    return run_init(
        Config(),
        project_dir=tmp_path,
        interactive=interactive,
        plain_prompt=prompt,
        secret_prompt=prompt,
        confirm=lambda label: confirm,
        install_browser=installer or (lambda: True),
    )


def test_creates_dirs_config_and_env_from_nothing(tmp_path, monkeypatch):
    _clear_env(monkeypatch)
    report = _run(
        tmp_path,
        answers={"ANTHROPIC_API_KEY": "sk-test-123", "BGG_USERNAME": "eric"},
    )
    assert (tmp_path / "photos").is_dir() and (tmp_path / "data").is_dir()
    assert (tmp_path / "config.toml").exists()
    env = (tmp_path / ".env").read_text()
    assert "ANTHROPIC_API_KEY='sk-test-123'" in env
    assert "BGG_USERNAME='eric'" in env
    assert report.keys_written == ["ANTHROPIC_API_KEY", "BGG_USERNAME"]
    assert set(report.keys_missing) == {"BGG_PASSWORD", "BGG_API_TOKEN"}


def test_env_file_gets_owner_only_permissions(tmp_path, monkeypatch):
    _clear_env(monkeypatch)
    _run(tmp_path, answers={"BGG_PASSWORD": "hunter2hunter2"})
    mode = os.stat(tmp_path / ".env").st_mode & 0o777
    assert mode == 0o600


def test_rerun_prompts_only_for_missing_keys(tmp_path, monkeypatch):
    _clear_env(monkeypatch)
    _run(tmp_path, answers={"BGG_USERNAME": "eric"})
    before = (tmp_path / ".env").read_text()

    report = _run(tmp_path, answers={"BGG_API_TOKEN": "tok-abc"})
    env = (tmp_path / ".env").read_text()
    assert env.startswith(before)  # existing content untouched, appended only
    assert "BGG_USERNAME" in report.keys_ready  # not re-prompted
    assert report.keys_written == ["BGG_API_TOKEN"]


def test_env_vars_count_as_configured(tmp_path, monkeypatch):
    _clear_env(monkeypatch)
    monkeypatch.setenv("ANTHROPIC_API_KEY", "sk-from-direnv")
    report = _run(tmp_path)
    assert "ANTHROPIC_API_KEY" in report.keys_ready
    assert not (tmp_path / ".env").exists()  # nothing to write


def test_non_interactive_reports_without_prompting(tmp_path, monkeypatch):
    _clear_env(monkeypatch)

    def explode(label: str) -> str:
        raise AssertionError("prompted without a TTY")

    report = run_init(
        Config(),
        project_dir=tmp_path,
        interactive=False,
        plain_prompt=explode,
        secret_prompt=explode,
        confirm=lambda label: (_ for _ in ()).throw(AssertionError("confirmed")),
        install_browser=lambda: True,
    )
    assert len(report.keys_missing) == 4
    assert not report.browser_installed


def test_existing_config_and_dirs_are_left_alone(tmp_path, monkeypatch):
    _clear_env(monkeypatch)
    (tmp_path / "photos").mkdir()
    (tmp_path / "config.toml").write_text('photos_dir = "shots"\n')
    report = _run(tmp_path)
    assert (tmp_path / "config.toml").read_text() == 'photos_dir = "shots"\n'
    assert not report.wrote_config


def test_browser_install_runs_only_on_confirm(tmp_path, monkeypatch):
    _clear_env(monkeypatch)
    ran = []
    _run(tmp_path, confirm=True, installer=lambda: ran.append(1) or True)
    assert ran == [1]
    _run(tmp_path, confirm=False, installer=lambda: ran.append(2) or True)
    assert ran == [1]


def test_secret_values_never_appear_in_output(tmp_path, monkeypatch, capsys):
    _clear_env(monkeypatch)
    _run(tmp_path, answers={"BGG_PASSWORD": "s3cret-value-xyz"})
    assert "s3cret-value-xyz" not in capsys.readouterr().out


def test_values_are_shell_quoted_for_source(tmp_path, monkeypatch):
    # a password with spaces, $, and quotes must survive `source .env`
    _clear_env(monkeypatch)
    _run(tmp_path, answers={"BGG_PASSWORD": "pa$s wo'rd"})
    env = (tmp_path / ".env").read_text()
    assert "BGG_PASSWORD='pa$s wo'\\''rd'" in env


def test_env_parsing_negatives(tmp_path, monkeypatch):
    # commented, quoted-empty, and export-prefixed lines must parse sanely
    _clear_env(monkeypatch)
    (tmp_path / ".env").write_text(
        "# BGG_PASSWORD=commented-out\n"
        'ANTHROPIC_API_KEY=""\n'
        "export BGG_USERNAME='eric'\n"
    )
    report = _run(tmp_path)
    assert "BGG_USERNAME" in report.keys_ready  # export form recognized
    assert "ANTHROPIC_API_KEY" in report.keys_missing  # quoted-empty ≠ set
    assert "BGG_PASSWORD" in report.keys_missing  # comments don't count


def test_env_file_is_owner_only_from_creation(tmp_path, monkeypatch):
    import os as _os

    _clear_env(monkeypatch)
    _run(tmp_path, answers={"BGG_API_TOKEN": "tok-123"})
    assert _os.stat(tmp_path / ".env").st_mode & 0o777 == 0o600
