"""Tests for feature flags CLI commands."""

from __future__ import annotations

import json
import os
from typing import TYPE_CHECKING

import pytest
from click.testing import CliRunner

if TYPE_CHECKING:
    from collections.abc import Generator

from augint_library.cli import cli
from augint_library.feature_flags import FeatureFlags


@pytest.fixture
def runner() -> CliRunner:
    """Create a Click test runner."""
    return CliRunner()


@pytest.fixture
def clean_flags() -> Generator[None, None, None]:
    """Reset the global flags instance before each test."""
    FeatureFlags._instance = None
    yield
    FeatureFlags._instance = None


class TestFeatureFlagsCLI:
    """Test feature flags CLI commands."""

    def test_list_no_flags(self, runner: CliRunner, clean_flags: None) -> None:
        """Test listing when no flags are registered."""
        result = runner.invoke(cli, ["feature-flags", "list"])
        assert result.exit_code == 0
        assert "No feature flags registered" in result.output

    def test_list_flags(self, runner: CliRunner, clean_flags: None) -> None:
        """Test listing registered flags."""
        # Register some flags
        flags = FeatureFlags()
        flags.register("feature1", default="enabled", description="First feature")
        flags.register("feature2", default="percentage:50", metadata={"owner": "team-a"})

        result = runner.invoke(cli, ["feature-flags", "list"])
        assert result.exit_code == 0
        assert "Feature Flags:" in result.output
        assert "Name: feature1" in result.output
        assert "State: enabled" in result.output
        assert "Description: First feature" in result.output
        assert "Name: feature2" in result.output
        assert "State: percentage:50" in result.output
        assert "Metadata: {'owner': 'team-a'}" in result.output

    def test_list_flags_json(self, runner: CliRunner, clean_flags: None) -> None:
        """Test listing flags in JSON format."""
        flags = FeatureFlags()
        flags.register("feature1", default="enabled")

        result = runner.invoke(cli, ["feature-flags", "list", "--json"])
        assert result.exit_code == 0

        output = json.loads(result.output)
        assert "feature1" in output
        assert output["feature1"]["state"] == "enabled"
        assert output["feature1"]["default"] == "enabled"

    @pytest.mark.skipif(
        "CI" in os.environ,
        reason="Click runner has I/O issues in GitHub Actions",
    )
    def test_set_flag_state(self, runner: CliRunner, clean_flags: None) -> None:
        """Test setting flag state."""
        flags = FeatureFlags()
        flags.register("test_flag", default="disabled")

        result = runner.invoke(cli, ["feature-flags", "set", "test_flag", "enabled"])
        assert result.exit_code == 0
        assert "Set feature flag 'test_flag' to 'enabled'" in result.output

        # Note: Cannot verify state change here due to subprocess isolation in CliRunner

    @pytest.mark.skipif(
        "CI" in os.environ,
        reason="Click runner has I/O issues in GitHub Actions",
    )
    def test_set_flag_percentage(self, runner: CliRunner, clean_flags: None) -> None:
        """Test setting flag to percentage state."""
        flags = FeatureFlags()
        flags.register("test_flag")

        result = runner.invoke(cli, ["feature-flags", "set", "test_flag", "percentage:75"])
        assert result.exit_code == 0
        assert "Set feature flag 'test_flag' to 'percentage:75'" in result.output

    def test_set_unknown_flag(self, runner: CliRunner, clean_flags: None) -> None:
        """Test setting unknown flag."""
        result = runner.invoke(cli, ["feature-flags", "set", "unknown_flag", "enabled"])
        assert result.exit_code != 0
        assert "Error:" in result.output
        assert "Unknown feature flag" in result.output

    def test_set_invalid_state(self, runner: CliRunner, clean_flags: None) -> None:
        """Test setting invalid state."""
        flags = FeatureFlags()
        flags.register("test_flag")

        result = runner.invoke(cli, ["feature-flags", "set", "test_flag", "invalid"])
        assert result.exit_code != 0
        assert "Error:" in result.output
        assert "Invalid state" in result.output

    def test_check_flag(self, runner: CliRunner, clean_flags: None) -> None:
        """Test checking flag state."""
        flags = FeatureFlags()
        flags.register("test_flag", default="enabled")

        result = runner.invoke(cli, ["feature-flags", "check", "test_flag"])
        assert result.exit_code == 0
        assert "Flag: test_flag" in result.output
        assert "State: enabled" in result.output
        assert "Enabled: Yes" in result.output

    def test_check_flag_with_context(self, runner: CliRunner, clean_flags: None) -> None:
        """Test checking flag with context."""
        flags = FeatureFlags()
        flags.register("test_flag", default="percentage:50")

        result = runner.invoke(
            cli,
            [
                "feature-flags",
                "check",
                "test_flag",
                "--user-id",
                "user123",
                "--environment",
                "prod",
            ],
        )
        assert result.exit_code == 0
        assert "Context: {'user_id': 'user123', 'environment': 'prod'}" in result.output

    @pytest.mark.skipif(
        "CI" in os.environ,
        reason="Click runner has I/O issues in GitHub Actions",
    )
    def test_check_unknown_flag(self, runner: CliRunner, clean_flags: None) -> None:
        """Test checking unknown flag."""
        result = runner.invoke(cli, ["feature-flags", "check", "unknown_flag"])
        # Should succeed but show flag as disabled (warning is logged)
        assert result.exit_code == 0
        assert "State: unknown (defaulting to disabled)" in result.output
        assert "Enabled: No" in result.output

    def test_register_flag(self, runner: CliRunner, clean_flags: None) -> None:
        """Test registering a new flag."""
        result = runner.invoke(cli, ["feature-flags", "register", "new_flag"])
        assert result.exit_code == 0
        assert "Registered feature flag 'new_flag' with default state 'disabled'" in result.output

        # Verify flag was registered
        flags = FeatureFlags()
        assert "new_flag" in flags._flags
        assert flags.get_state("new_flag") == "disabled"

    def test_register_flag_with_options(self, runner: CliRunner, clean_flags: None) -> None:
        """Test registering flag with options."""
        result = runner.invoke(
            cli,
            [
                "feature-flags",
                "register",
                "new_flag",
                "--default",
                "percentage:30",
                "--description",
                "Test feature",
            ],
        )
        assert result.exit_code == 0
        assert (
            "Registered feature flag 'new_flag' with default state 'percentage:30'" in result.output
        )

        # Verify flag configuration
        flags = FeatureFlags()
        all_flags = flags.get_all_flags()
        assert all_flags["new_flag"]["state"] == "percentage:30"
        assert all_flags["new_flag"]["description"] == "Test feature"

    def test_register_invalid_name(self, runner: CliRunner, clean_flags: None) -> None:
        """Test registering flag with invalid name."""
        result = runner.invoke(cli, ["feature-flags", "register", "invalid.name"])
        assert result.exit_code != 0
        assert "Error:" in result.output
        assert "Invalid flag name" in result.output

    def test_register_invalid_default(self, runner: CliRunner, clean_flags: None) -> None:
        """Test registering flag with invalid default state."""
        result = runner.invoke(
            cli, ["feature-flags", "register", "test_flag", "--default", "invalid_state"]
        )
        assert result.exit_code != 0
        assert "Error:" in result.output
        assert "Invalid state" in result.output

    def test_cli_help(self, runner: CliRunner) -> None:
        """Test CLI help messages."""
        # Main feature-flags help
        result = runner.invoke(cli, ["feature-flags", "--help"])
        assert result.exit_code == 0
        assert "Manage feature flags" in result.output
        assert "list" in result.output
        assert "set" in result.output
        assert "check" in result.output
        assert "register" in result.output

        # Set command help
        result = runner.invoke(cli, ["feature-flags", "set", "--help"])
        assert result.exit_code == 0
        assert "STATE can be: enabled, disabled, percentage:N" in result.output

        # Check command help
        result = runner.invoke(cli, ["feature-flags", "check", "--help"])
        assert result.exit_code == 0
        assert "--user-id" in result.output
        assert "--environment" in result.output
