"""Tests for thin CLI entrypoint."""

from pathlib import Path
from types import SimpleNamespace

import pytest

from dotpromptz.cli import cli
from dotpromptz.errors import ExecutionConfigError


class TestCLIArguments:
    def test_no_arguments_shows_help_and_exits_2(self) -> None:
        with pytest.raises(SystemExit) as exc_info:
            cli([])
        assert exc_info.value.code == 2

    def test_help_flag_works(self, capsys: pytest.CaptureFixture[str]) -> None:
        with pytest.raises(SystemExit) as exc_info:
            cli(['--help'])
        assert exc_info.value.code == 0
        captured = capsys.readouterr()
        assert 'run' in captured.out
        assert 'build' in captured.out
        assert 'merge' in captured.out
        assert 'git' in captured.out


def test_upgrade_dispatches_to_upgrade_service(monkeypatch: pytest.MonkeyPatch) -> None:
    monkeypatch.setattr('dotpromptz.cli.configure_logging', lambda level: Path('/tmp'))
    monkeypatch.setattr('dotpromptz.cli.run_upgrade', lambda: 0)
    with pytest.raises(SystemExit) as exc_info:
        cli(['--upgrade'])
    assert exc_info.value.code == 0


def test_build_dispatches_to_build_service(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
    calls: dict[str, object] = {}

    def _fake_build(prompt_file: str, *, log_dir: Path) -> object:
        calls['prompt_file'] = prompt_file
        calls['log_dir'] = log_dir
        return object()

    monkeypatch.setattr('dotpromptz.cli.configure_logging', lambda level: tmp_path)
    monkeypatch.setattr('dotpromptz.cli.build_prompt', _fake_build)

    with pytest.raises(SystemExit) as exc_info:
        cli(['build', 'a.prompt'])

    assert exc_info.value.code == 0
    assert calls == {'prompt_file': 'a.prompt', 'log_dir': tmp_path}


def test_run_dispatches_to_run_service(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
    calls: dict[str, object] = {}

    async def _fake_run(prompt_file: str, *, log_dir: Path, force: bool = False) -> object:
        calls['prompt_file'] = prompt_file
        calls['log_dir'] = log_dir
        calls['force'] = force
        return SimpleNamespace(all_failed=False)

    monkeypatch.setattr('dotpromptz.cli.configure_logging', lambda level: tmp_path)
    monkeypatch.setattr('dotpromptz.cli.run_prompt', _fake_run)

    with pytest.raises(SystemExit) as exc_info:
        cli(['run', 'a.prompt', '--force'])

    assert exc_info.value.code == 0
    assert calls == {'prompt_file': 'a.prompt', 'log_dir': tmp_path, 'force': True}


def test_run_all_failed_exits_1(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
    async def _fake_run(prompt_file: str, *, log_dir: Path, force: bool = False) -> object:
        return SimpleNamespace(all_failed=True)

    monkeypatch.setattr('dotpromptz.cli.configure_logging', lambda level: tmp_path)
    monkeypatch.setattr('dotpromptz.cli.run_prompt', _fake_run)

    with pytest.raises(SystemExit) as exc_info:
        cli(['run', 'a.prompt'])

    assert exc_info.value.code == 1


def test_merge_dispatches_to_merge_module(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
    calls: dict[str, object] = {}

    def _fake_merge(directory: Path, *, pattern: str | None, with_filename: bool, force: bool) -> Path:
        calls['directory'] = directory
        calls['pattern'] = pattern
        calls['with_filename'] = with_filename
        calls['force'] = force
        return tmp_path / 'merged.jsonl'

    monkeypatch.setattr('dotpromptz.cli.configure_logging', lambda level: tmp_path)
    monkeypatch.setattr('dotpromptz.cli.merge_directory', _fake_merge)

    with pytest.raises(SystemExit) as exc_info:
        cli(['merge', str(tmp_path), '--pattern', '*.json', '-W', '--force'])

    assert exc_info.value.code == 0
    assert calls == {
        'directory': tmp_path,
        'pattern': '*.json',
        'with_filename': True,
        'force': True,
    }


def test_domain_error_maps_to_exit_2(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
    def _fake_build(prompt_file: str, *, log_dir: Path) -> object:
        raise ExecutionConfigError('bad output', code='output_bad')

    monkeypatch.setattr('dotpromptz.cli.configure_logging', lambda level: tmp_path)
    monkeypatch.setattr('dotpromptz.cli.build_prompt', _fake_build)

    with pytest.raises(SystemExit) as exc_info:
        cli(['build', 'a.prompt'])

    assert exc_info.value.code == 2


def test_git_sync_dispatches(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
    calls: dict[str, object] = {'called': False}

    def _fake_sync() -> None:
        calls['called'] = True

    monkeypatch.setattr('dotpromptz.cli.configure_logging', lambda level: tmp_path)
    monkeypatch.setattr('dotpromptz.cli.sync_repo', _fake_sync)

    with pytest.raises(SystemExit) as exc_info:
        cli(['git', 'sync'])

    assert exc_info.value.code == 0
    assert calls['called'] is True


def test_git_push_dispatches(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
    calls: dict[str, object] = {'called': False}

    def _fake_push() -> object:
        calls['called'] = True
        return object()

    monkeypatch.setattr('dotpromptz.cli.configure_logging', lambda level: tmp_path)
    monkeypatch.setattr('dotpromptz.cli.commit_and_push', _fake_push)

    with pytest.raises(SystemExit) as exc_info:
        cli(['git', 'push'])

    assert exc_info.value.code == 0
    assert calls['called'] is True


def test_git_submit_dispatches(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None:
    calls: dict[str, object] = {}

    def _fake_submit(prompt_file: str, *, send_mail: bool) -> object:
        calls['prompt_file'] = prompt_file
        calls['send_mail'] = send_mail
        return object()

    monkeypatch.setattr('dotpromptz.cli.configure_logging', lambda level: tmp_path)
    monkeypatch.setattr('dotpromptz.cli.submit_prompt', _fake_submit)

    with pytest.raises(SystemExit) as exc_info:
        cli(['git', 'submit', 'abc.prompt', '--no-mail'])

    assert exc_info.value.code == 0
    assert calls == {'prompt_file': 'abc.prompt', 'send_mail': False}
