"""Tests for dynamic CLI options."""

from __future__ import annotations

import json

from cli.config import CONFIG_DIR_ENV, CLIConfig, ConfigStore
from cli.options import DynamicProjectHelp, project_option


class TestDynamicProjectHelp:
    """Tests for DynamicProjectHelp class."""

    def test_shows_current_project_when_set(self, tmp_path, monkeypatch):
        """Help text should show current project when configured."""
        monkeypatch.setenv(CONFIG_DIR_ENV, str(tmp_path))
        store = ConfigStore()
        store.save(CLIConfig(default_project="my-project"))

        help_obj = DynamicProjectHelp()
        help_text = str(help_obj)

        assert help_text == "Project key (current: my-project)"

    def test_shows_not_set_when_no_default_project(self, tmp_path, monkeypatch):
        """Help text should show 'not set' when no default project configured."""
        monkeypatch.setenv(CONFIG_DIR_ENV, str(tmp_path))
        # Create config file without default_project
        store = ConfigStore()
        store.save(CLIConfig(api_base_url="http://example.com"))

        help_obj = DynamicProjectHelp()
        help_text = str(help_obj)

        assert help_text == "Project key (current: not set)"

    def test_shows_not_set_when_config_file_missing(self, tmp_path, monkeypatch):
        """Help text should show 'not set' when config file doesn't exist."""
        monkeypatch.setenv(CONFIG_DIR_ENV, str(tmp_path))
        # Don't create any config file

        help_obj = DynamicProjectHelp()
        help_text = str(help_obj)

        assert help_text == "Project key (current: not set)"

    def test_shows_unknown_on_invalid_json(self, tmp_path, monkeypatch):
        """Help text should show 'unknown' when config file is invalid JSON."""
        monkeypatch.setenv(CONFIG_DIR_ENV, str(tmp_path))
        config_path = tmp_path / "config.json"
        config_path.write_text("{ invalid json }")

        help_obj = DynamicProjectHelp()
        help_text = str(help_obj)

        assert help_text == "Project key (current: unknown)"

    def test_respects_env_override(self, tmp_path, monkeypatch):
        """Help text should show env override project when set."""
        monkeypatch.setenv(CONFIG_DIR_ENV, str(tmp_path))
        monkeypatch.setenv("CLI__DEFAULT_PROJECT", "env-project")
        # Create file config with different project
        store = ConfigStore()
        store.save(CLIConfig(default_project="file-project"))

        help_obj = DynamicProjectHelp()
        help_text = str(help_obj)

        # Env override takes precedence
        assert help_text == "Project key (current: env-project)"

    def test_shows_unknown_on_permission_error(self, tmp_path, monkeypatch):
        """Help text should show 'unknown' when config file is not readable."""
        monkeypatch.setenv(CONFIG_DIR_ENV, str(tmp_path))
        config_path = tmp_path / "config.json"
        config_path.write_text(json.dumps({"default_project": "test"}))
        # Make file unreadable
        config_path.chmod(0o000)

        try:
            help_obj = DynamicProjectHelp()
            help_text = str(help_obj)
            # Should gracefully degrade
            assert help_text == "Project key (current: unknown)"
        finally:
            # Restore permissions for cleanup
            config_path.chmod(0o644)


class TestProjectOption:
    """Tests for project_option factory function."""

    def test_returns_typer_option_info(self):
        """project_option() should return a typer OptionInfo object."""
        import typer

        option = project_option()
        # Should return an OptionInfo (Typer's representation of an option default)
        assert isinstance(option, typer.models.OptionInfo)

    def test_accepts_additional_kwargs(self):
        """project_option() should accept additional typer.Option kwargs."""
        import typer

        # Just verify it doesn't raise and returns OptionInfo
        option = project_option(envvar="TEST_PROJECT")
        assert isinstance(option, typer.models.OptionInfo)


class TestDynamicHelpIntegration:
    """Integration tests for dynamic help with Typer."""

    def test_help_text_evaluated_at_render_time(self, tmp_path, monkeypatch):
        """Help text should be evaluated when __str__ is called, not at import."""
        monkeypatch.setenv(CONFIG_DIR_ENV, str(tmp_path))

        # Create help object before config exists
        help_obj = DynamicProjectHelp()

        # First call - no config file
        text1 = str(help_obj)
        assert "not set" in text1

        # Now create config
        store = ConfigStore()
        store.save(CLIConfig(default_project="new-project"))

        # Second call - should reflect new config
        text2 = str(help_obj)
        assert "new-project" in text2
