"""Test setup commands."""

from unittest.mock import Mock, patch

from click.testing import CliRunner

from augint_billing_lib.cli.setup import setup_group
from augint_billing_lib.cli.setup.activate_eventbus import activate_eventbus
from augint_billing_lib.cli.setup.eventbridge import eventbridge
from augint_billing_lib.cli.setup.stripe_product import stripe_product
from augint_billing_lib.cli.setup.verify import verify

# Removed MeterSupportDetector tests - no longer needed since we only support meter-based pricing


class TestStripeProductCommand:
    """Test stripe-product command."""

    def test_stripe_product_dry_run(self):
        """Test stripe-product in dry run mode."""
        runner = CliRunner()

        with patch("augint_billing_lib.cli.setup.stripe_product.config") as mock_config:
            mock_config.stripe_secret_key = "sk_test_mock"

            with patch("stripe.Product") as mock_product:
                mock_product.list.return_value = Mock(data=[])

                result = runner.invoke(
                    stripe_product,
                    ["--dry-run"],
                )

                assert result.exit_code == 0
                assert "DRY RUN" in result.output

    def test_stripe_product_no_api_key(self):
        """Test stripe-product with missing API key."""
        runner = CliRunner()

        with patch("augint_billing_lib.cli.setup.stripe_product.config") as mock_config:
            mock_config.stripe_secret_key = None

            result = runner.invoke(stripe_product)

            assert result.exit_code == 1
            assert "No Stripe API key" in result.output

    @patch("stripe.Product")
    @patch("stripe.Price")
    def test_stripe_product_creates_product(self, mock_price, mock_product):
        """Test creating a new product."""
        runner = CliRunner()

        # Mock Stripe responses
        mock_product.list.return_value = Mock(data=[])
        mock_product.create.return_value = Mock(id="prod_test123")
        mock_price.list.return_value = Mock(data=[])
        mock_price.create.return_value = Mock(id="price_test123")

        with patch("augint_billing_lib.cli.setup.stripe_product.config") as mock_config:
            mock_config.stripe_secret_key = "sk_test_mock"

            # Mock the meter creation
            with patch(
                "augint_billing_lib.cli.setup.stripe_product.create_meter_based_price"
            ) as mock_create:
                mock_create.return_value = (Mock(id="price_test123"), Mock(id="meter_test123"))

                result = runner.invoke(
                    stripe_product,
                    ["--update-env"],
                )

                assert result.exit_code == 0
                assert "Created product" in result.output
                mock_product.create.assert_called_once()


class TestEventBridgeCommand:
    """Test eventbridge command."""

    def test_eventbridge_dry_run(self):
        """Test eventbridge in dry run mode."""
        runner = CliRunner()

        with patch("augint_billing_lib.cli.setup.eventbridge.config") as mock_config:
            mock_config.stripe_secret_key = "sk_test_mock"
            mock_config.region = "us-east-1"

            result = runner.invoke(
                eventbridge,
                ["--aws-account-id", "123456789012", "--dry-run"],
            )

            assert result.exit_code == 0
            assert "DRY RUN" in result.output

    def test_eventbridge_no_region(self):
        """Test eventbridge with missing region."""
        runner = CliRunner()

        with patch("augint_billing_lib.cli.setup.eventbridge.config") as mock_config:
            mock_config.stripe_secret_key = "sk_test_mock"
            mock_config.region = None

            result = runner.invoke(
                eventbridge,
                ["--aws-account-id", "123456789012"],
            )

            assert result.exit_code == 1
            assert "AWS region not specified" in result.output


class TestActivateEventBusCommand:
    """Test activate-eventbus command."""

    @patch("boto3.client")
    def test_activate_eventbus_dry_run(self, mock_boto):
        """Test activate-eventbus in dry run mode."""
        runner = CliRunner()

        mock_events = Mock()
        mock_boto.return_value = mock_events

        mock_events.list_event_sources.return_value = {
            "EventSources": [
                {
                    "Name": "test-source",
                    "Arn": "arn:aws:events:us-east-1:123456789012:event-source/test",
                    "State": "PENDING",
                }
            ]
        }

        result = runner.invoke(activate_eventbus, ["--dry-run"])

        assert result.exit_code == 0
        assert "DRY RUN" in result.output
        assert "Would activate" in result.output

    @patch("boto3.client")
    def test_activate_eventbus_no_sources(self, mock_boto):
        """Test activate-eventbus with no sources found."""
        runner = CliRunner()

        mock_events = Mock()
        mock_boto.return_value = mock_events

        mock_events.list_event_sources.return_value = {"EventSources": []}

        result = runner.invoke(activate_eventbus)

        assert result.exit_code == 1
        assert "No Stripe partner event sources found" in result.output

    @patch("boto3.client")
    def test_activate_eventbus_already_active(self, mock_boto):
        """Test activate-eventbus with already active source."""
        runner = CliRunner()

        mock_events = Mock()
        mock_boto.return_value = mock_events

        mock_events.list_event_sources.return_value = {
            "EventSources": [
                {
                    "Name": "test-source",
                    "Arn": "arn:aws:events:us-east-1:123456789012:event-source/test",
                    "State": "ACTIVE",
                }
            ]
        }

        result = runner.invoke(activate_eventbus)

        assert result.exit_code == 0
        assert "already active" in result.output


class TestVerifyCommand:
    """Test verify command."""

    @patch("boto3.client")
    @patch("stripe.billing.Meter")
    @patch("stripe.Price")
    @patch("stripe.Product")
    @patch("stripe.Account")
    def test_verify_all_pass(self, mock_account, mock_product, mock_price, mock_meter, mock_boto):
        """Test verify with all checks passing."""
        runner = CliRunner()

        # Mock Stripe
        mock_account.retrieve.return_value = Mock(id="acct_test")
        mock_product.list.return_value = Mock(
            data=[Mock(id="prod_test", metadata={"created_by": "ai-billing-cli"})]
        )
        mock_price.list.return_value = Mock(
            data=[Mock(id="price_test", recurring={"usage_type": "metered"})]
        )
        mock_meter.list.return_value = Mock(data=[])

        # Mock AWS
        mock_events = Mock()
        mock_lambda = Mock()
        mock_dynamodb = Mock()
        mock_apigw = Mock()

        def client_factory(service, **kwargs):
            if service == "events":
                return mock_events
            if service == "lambda":
                return mock_lambda
            if service == "dynamodb":
                return mock_dynamodb
            if service == "apigateway":
                return mock_apigw
            return Mock()

        mock_boto.side_effect = client_factory

        mock_events.list_event_sources.return_value = {
            "EventSources": [
                {
                    "Name": "test",
                    "State": "ACTIVE",
                }
            ]
        }
        mock_events.list_event_buses.return_value = {"EventBuses": [{"Name": "stripe-test"}]}
        mock_events.list_rules.return_value = {"Rules": [{"Name": "test-rule", "State": "ENABLED"}]}

        mock_lambda.list_functions.return_value = {
            "Functions": [{"FunctionName": "test-stack-billing"}]
        }

        mock_dynamodb.describe_table.return_value = {
            "Table": {
                "ItemCount": 10,
                "TableStatus": "ACTIVE",
                "GlobalSecondaryIndexes": [{"IndexName": "gsi_stripe_customer"}],
            }
        }

        mock_apigw.get_usage_plan.return_value = {"id": "test-plan"}

        with patch("augint_billing_lib.cli.setup.verify.config") as mock_config:
            mock_config.stripe_secret_key = "sk_test_mock"
            mock_config.region = "us-east-1"
            mock_config.stack_name = "test-stack"
            mock_config.table_name = "test-table"
            mock_config.free_usage_plan_id = "free"
            mock_config.metered_usage_plan_id = "metered"

            result = runner.invoke(verify, ["--output", "text"])

            assert result.exit_code == 0
            assert "System is fully configured" in result.output or "passed" in result.output

    @patch("boto3.client")
    @patch("stripe.Account")
    def test_verify_with_failures(self, mock_account, mock_boto):
        """Test verify with some failures."""
        runner = CliRunner()

        # Mock Stripe failure
        import stripe

        mock_account.retrieve.side_effect = stripe.error.AuthenticationError("Invalid API key")

        # Mock AWS clients
        mock_events = Mock()
        mock_boto.return_value = mock_events
        mock_events.list_event_sources.return_value = {"EventSources": []}

        with patch("augint_billing_lib.cli.setup.verify.config") as mock_config:
            mock_config.stripe_secret_key = "sk_test_invalid"
            mock_config.region = "us-east-1"
            mock_config.stack_name = "test-stack"
            mock_config.table_name = "test-table"
            mock_config.free_usage_plan_id = "free"
            mock_config.metered_usage_plan_id = "metered"

            result = runner.invoke(verify, ["--output", "text"])

            assert result.exit_code == 1
            assert "Invalid API key" in result.output or "fail" in result.output.lower()


class TestSetupGroup:
    """Test setup command group."""

    def test_setup_group_help(self):
        """Test setup group help text."""
        runner = CliRunner()
        result = runner.invoke(setup_group, ["--help"])

        assert result.exit_code == 0
        assert "Setup and initialization commands" in result.output
        assert "stripe-product" in result.output
        assert "eventbridge" in result.output
        assert "activate-eventbus" in result.output
        assert "verify" in result.output
