"""Tests for the dotprompt CLI."""

from pathlib import Path
from unittest.mock import MagicMock

import pytest

from dotpromptz.cli import (
    _resolve_adapter,
    _resolve_file_name,
    cli,
)

SIMPLE_PROMPT = """\
---
config:
  model: gpt-4o
input:
  schema:
    topic: string
---
Tell me about {{topic}}.
"""

PROMPT_WITH_INLINE_DATA = """\
---
config:
  model: gpt-4o
input:
  data:
    topic: AI
---
Tell me about {{topic}}.
"""


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

    def test_nonexistent_file_shows_error(self, capsys: pytest.CaptureFixture[str]) -> None:
        with pytest.raises(SystemExit) as exc_info:
            cli(['/nonexistent/file.prompt'])
        assert exc_info.value.code == 2
        captured = capsys.readouterr()
        assert 'does not exist' in captured.err.lower() or 'exist' in captured.err.lower()

    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 '.prompt' in captured.out


class TestResolveAdapterCLIWrapper:
    """Tests that the CLI wrapper converts ValueError → sys.exit(2)."""

    def test_none_adapter_exits(self) -> None:
        mock_rendered = MagicMock()
        mock_rendered.adapter = None
        mock_rendered.config = {'model': 'gpt-4o'}

        with pytest.raises(SystemExit) as exc_info:
            _resolve_adapter(mock_rendered)
        assert exc_info.value.code == 2

    def test_no_adapter_no_model_exits(self) -> None:
        mock_rendered = MagicMock()
        mock_rendered.adapter = None
        mock_rendered.config = {}

        with pytest.raises(SystemExit) as exc_info:
            _resolve_adapter(mock_rendered)
        assert exc_info.value.code == 2


class TestResolveFileName:
    """Tests for _resolve_file_name — single Handlebars pass with UPPERCASE variable keys."""

    def test_static_file_name_unchanged(self) -> None:
        result = _resolve_file_name('report', Path('/tmp/my_prompt.prompt'))
        assert result == 'report'

    def test_at_name_resolves_to_prompt_stem(self) -> None:
        result = _resolve_file_name('{{NAME}}_output', Path('/tmp/my_prompt.prompt'))
        assert result == 'my_prompt_output'

    def test_at_time_resolves_to_timestamp(self) -> None:
        result = _resolve_file_name('{{TIME}}', Path('/tmp/x.prompt'))
        # Timestamp format: YYYYMMDD_HHMMSS (15 chars)
        assert len(result) == 15
        assert result[8] == '_'

    def test_at_index_resolves_when_provided(self) -> None:
        result = _resolve_file_name('item_{{INDEX}}', Path('/tmp/x.prompt'), index=3)
        assert result == 'item_3'

    def test_at_index_absent_when_not_provided(self) -> None:
        result = _resolve_file_name('item_{{INDEX}}', Path('/tmp/x.prompt'))
        # INDEX not provided → Handlebars renders empty string for missing data var
        assert result == 'item_'

    def test_input_variable_resolves(self) -> None:
        result = _resolve_file_name('profile_{{name}}', Path('/tmp/x.prompt'), item_vars={'name': 'alice'})
        assert result == 'profile_alice'

    def test_multiple_variables_combined(self) -> None:
        result = _resolve_file_name(
            '{{NAME}}_{{lang}}_{{INDEX}}',
            Path('/tmp/translate.prompt'),
            item_vars={'lang': 'zh'},
            index=2,
        )
        assert result == 'translate_zh_2'

    def test_at_name_and_input_name_coexist(self) -> None:
        """{{NAME}} and {{name}} resolve independently — no shadowing.

        UPPERCASE @-variable keys (NAME) in Handlebars data namespace
        never conflict with lowercase input variables (name) in context.
        """
        result = _resolve_file_name(
            '{{NAME}}_{{name}}',
            Path('/tmp/my_prompt.prompt'),
            item_vars={'name': 'alice'},
        )
        assert result == 'my_prompt_alice'

    def test_different_named_vars_no_conflict(self) -> None:
        """Input var 'user' does not conflict with NAME."""
        result = _resolve_file_name(
            '{{NAME}}_{{user}}',
            Path('/tmp/my_prompt.prompt'),
            item_vars={'user': 'alice'},
        )
        assert result == 'my_prompt_alice'

    def test_empty_item_vars(self) -> None:
        result = _resolve_file_name('{{NAME}}', Path('/tmp/x.prompt'), item_vars={})
        assert result == 'x'

    def test_none_item_vars(self) -> None:
        result = _resolve_file_name('{{NAME}}', Path('/tmp/x.prompt'), item_vars=None)
        assert result == 'x'
