from io import StringIO

import pytest
from django.core.management import call_command

from servala.core.models import User


@pytest.mark.django_db
class TestMakeSuperuserCommand:
    def test_make_superuser_success(self):
        user = User.objects.create(
            email="test@example.com", is_staff=False, is_superuser=False
        )

        out = StringIO()
        call_command("make_superuser", "test@example.com", stdout=out)

        user.refresh_from_db()
        assert user.is_superuser is True
        assert user.is_staff is True
        assert "is now a superuser" in out.getvalue()

    def test_make_superuser_case_insensitive(self):
        user = User.objects.create(
            email="Test@Example.com", is_staff=False, is_superuser=False
        )

        out = StringIO()
        call_command("make_superuser", "TEST@EXAMPLE.COM", stdout=out)

        user.refresh_from_db()
        assert user.is_superuser is True

    def test_make_superuser_user_not_found(self):
        out = StringIO()
        call_command("make_superuser", "nonexistent@example.com", stdout=out)

        assert "No matching user found" in out.getvalue()


@pytest.mark.django_db
class TestMakeStaffUserCommand:
    def test_make_staff_user_success(self):
        user = User.objects.create(email="staff@example.com", is_staff=False)

        out = StringIO()
        call_command("make_staff_user", "staff@example.com", stdout=out)

        user.refresh_from_db()
        assert user.is_staff is True
        assert "Made 1 user(s) into staff users" in out.getvalue()

    def test_make_staff_user_multiple(self):
        user1 = User.objects.create(email="staff1@example.com", is_staff=False)
        user2 = User.objects.create(email="staff2@example.com", is_staff=False)

        out = StringIO()
        call_command(
            "make_staff_user", "staff1@example.com", "staff2@example.com", stdout=out
        )

        user1.refresh_from_db()
        user2.refresh_from_db()
        assert user1.is_staff is True
        assert user2.is_staff is True
        assert "Made 2 user(s) into staff users" in out.getvalue()

    def test_make_staff_user_no_emails(self):
        out = StringIO()
        call_command("make_staff_user", stdout=out)

        assert "No email addresses provided" in out.getvalue()

    def test_make_staff_user_already_staff(self):
        User.objects.create(email="already@example.com", is_staff=True)

        out = StringIO()
        call_command("make_staff_user", "already@example.com", stdout=out)

        output = out.getvalue()
        assert "already staff" in output
        assert "No matching non-staff users found" in output

    def test_make_staff_user_substring_match(self):
        user1 = User.objects.create(email="user@company.com", is_staff=False)
        user2 = User.objects.create(email="admin@company.com", is_staff=False)
        user3 = User.objects.create(email="other@different.com", is_staff=False)

        out = StringIO()
        call_command("make_staff_user", "@company.com", "--substring", stdout=out)

        user1.refresh_from_db()
        user2.refresh_from_db()
        user3.refresh_from_db()
        assert user1.is_staff is True
        assert user2.is_staff is True
        assert user3.is_staff is False
        assert "Made 2 user(s) into staff users" in out.getvalue()


@pytest.mark.django_db
class TestReencryptFieldsCommand:
    def test_reencrypt_fields_no_control_planes(self):
        out = StringIO()
        call_command("reencrypt_fields", stdout=out)

        output = out.getvalue()
        assert "Starting re-encryption" in output
        assert "Re-encrypted 0 ControlPlane objects" in output

    def test_reencrypt_fields_with_control_plane(self, control_plane):
        out = StringIO()
        call_command("reencrypt_fields", stdout=out)

        output = out.getvalue()
        assert "Re-encrypted 1 ControlPlane objects" in output


@pytest.mark.django_db
class TestSyncBillingMetadataCommand:
    def test_sync_billing_metadata_no_control_planes(self):
        out = StringIO()
        call_command("sync_billing_metadata", "--dry-run", stdout=out)

        output = out.getvalue()
        assert "DRY RUN" in output
        assert "Syncing billing metadata on 0 control plane(s)" in output
        assert "Sync completed" in output

    def test_sync_billing_metadata_conflicting_options(self):
        out = StringIO()
        call_command(
            "sync_billing_metadata",
            "--namespaces-only",
            "--instances-only",
            stdout=out,
        )

        assert (
            "Cannot use both --namespaces-only and --instances-only" in out.getvalue()
        )

    def test_sync_billing_metadata_invalid_control_plane_id(self):
        out = StringIO()
        call_command("sync_billing_metadata", "--control-plane", "99999", stdout=out)

        assert "No control planes found with the specified IDs" in out.getvalue()

    def test_sync_billing_metadata_dry_run_with_control_plane(self, control_plane):
        out = StringIO()
        call_command("sync_billing_metadata", "--dry-run", stdout=out)

        output = out.getvalue()
        assert "DRY RUN" in output
        assert "Syncing billing metadata on 1 control plane(s)" in output
        assert control_plane.name in output
