"""GraphQL tests for onboarding queries and mutations."""

import jwt
import pytest
from django.conf import settings
from django.contrib.auth.models import User

from accounts.models import (
    CompanySizeChoices,
    MarketingProfile,
    OnboardingProgress,
    RoleChoices,
)


def make_auth_header(user):
    """Create JWT auth header for a user."""
    token = jwt.encode(
        {"user_id": user.pk},
        settings.SECRET_KEY,
        algorithm="HS256",
    )
    return {"HTTP_AUTHORIZATION": f"Bearer {token}"}


@pytest.fixture
def user(db):
    """Create a test user."""
    user = User.objects.create_user(
        username="testuser",
        email="test@example.com",
        password="testpass123",
    )
    # Remove any auto-created records
    OnboardingProgress.objects.filter(user=user).delete()
    MarketingProfile.objects.filter(user=user).delete()
    return user


@pytest.fixture
def user_with_onboarding(user):
    """Create a user with onboarding records."""
    OnboardingProgress.objects.create(
        user=user,
        completed_welcome=True,
        completed_role=False,
    )
    MarketingProfile.objects.create(user=user)
    return user


class TestOnboardingProgressQuery:
    """Tests for onboardingProgress query."""

    QUERY = """
        query {
            onboardingProgress {
                id
                hasCompletedOnboarding
                completedWelcome
                completedRole
                completedCompany
                completedChannels
            }
        }
    """

    def test_returns_null_when_no_progress(self, client, user):
        """Should return null when user has no onboarding record."""
        response = client.post(
            "/graphql/",
            {"query": self.QUERY},
            content_type="application/json",
            **make_auth_header(user),
        )

        assert response.status_code == 200
        data = response.json()
        assert data["data"]["onboardingProgress"] is None

    def test_returns_progress_when_exists(self, client, user_with_onboarding):
        """Should return onboarding progress when it exists."""
        response = client.post(
            "/graphql/",
            {"query": self.QUERY},
            content_type="application/json",
            **make_auth_header(user_with_onboarding),
        )

        assert response.status_code == 200
        data = response.json()
        progress = data["data"]["onboardingProgress"]
        assert progress is not None
        assert progress["completedWelcome"] is True
        assert progress["completedRole"] is False

    def test_requires_authentication(self, client):
        """Should return null when not authenticated."""
        response = client.post(
            "/graphql/",
            {"query": self.QUERY},
            content_type="application/json",
        )

        assert response.status_code == 200
        data = response.json()
        assert data["data"]["onboardingProgress"] is None


class TestCompleteWelcomeStepMutation:
    """Tests for completeWelcomeStep mutation."""

    MUTATION = """
        mutation {
            completeWelcomeStep {
                id
                completedWelcome
                hasCompletedOnboarding
            }
        }
    """

    def test_marks_welcome_completed(self, client, user):
        """Should mark welcome step as completed."""
        response = client.post(
            "/graphql/",
            {"query": self.MUTATION},
            content_type="application/json",
            **make_auth_header(user),
        )

        assert response.status_code == 200
        data = response.json()
        assert "errors" not in data
        result = data["data"]["completeWelcomeStep"]
        assert result["completedWelcome"] is True
        assert result["hasCompletedOnboarding"] is False

    def test_requires_authentication(self, client):
        """Should fail when not authenticated."""
        response = client.post(
            "/graphql/",
            {"query": self.MUTATION},
            content_type="application/json",
        )

        assert response.status_code == 200
        data = response.json()
        assert "errors" in data


class TestUpdateOnboardingRoleMutation:
    """Tests for updateOnboardingRole mutation."""

    MUTATION = """
        mutation($input: UpdateOnboardingRoleInput!) {
            updateOnboardingRole(input: $input) {
                id
                completedRole
                hasCompletedOnboarding
            }
        }
    """

    def test_updates_role(self, client, user):
        """Should update role and mark step completed."""
        response = client.post(
            "/graphql/",
            {
                "query": self.MUTATION,
                "variables": {"input": {"role": "DEVREL", "skip": False}},
            },
            content_type="application/json",
            **make_auth_header(user),
        )

        assert response.status_code == 200
        data = response.json()
        assert "errors" not in data
        result = data["data"]["updateOnboardingRole"]
        assert result["completedRole"] is True

        # Verify role was saved
        profile = MarketingProfile.objects.get(user=user)
        assert profile.role == RoleChoices.DEVREL

    def test_skips_role(self, client, user):
        """Should mark step completed without saving role when skip=True."""
        response = client.post(
            "/graphql/",
            {
                "query": self.MUTATION,
                "variables": {"input": {"role": "DEVREL", "skip": True}},
            },
            content_type="application/json",
            **make_auth_header(user),
        )

        assert response.status_code == 200
        data = response.json()
        result = data["data"]["updateOnboardingRole"]
        assert result["completedRole"] is True

        # Verify role was NOT saved
        profile = MarketingProfile.objects.get(user=user)
        assert profile.role is None


class TestUpdateOnboardingCompanyMutation:
    """Tests for updateOnboardingCompany mutation."""

    MUTATION = """
        mutation($input: UpdateOnboardingCompanyInput!) {
            updateOnboardingCompany(input: $input) {
                id
                completedCompany
            }
        }
    """

    def test_updates_company_size(self, client, user):
        """Should update company size and mark step completed."""
        response = client.post(
            "/graphql/",
            {
                "query": self.MUTATION,
                "variables": {"input": {"companySize": "STARTUP", "skip": False}},
            },
            content_type="application/json",
            **make_auth_header(user),
        )

        assert response.status_code == 200
        data = response.json()
        assert "errors" not in data
        result = data["data"]["updateOnboardingCompany"]
        assert result["completedCompany"] is True

        # Verify company size was saved
        profile = MarketingProfile.objects.get(user=user)
        assert profile.company_size == CompanySizeChoices.STARTUP


class TestUpdateOnboardingChannelsMutation:
    """Tests for updateOnboardingChannels mutation."""

    MUTATION = """
        mutation($input: UpdateOnboardingChannelsInput!) {
            updateOnboardingChannels(input: $input) {
                id
                completedChannels
                hasCompletedOnboarding
            }
        }
    """

    def test_updates_channels_and_completes_onboarding(self, client, user):
        """Should update channels and complete onboarding."""
        response = client.post(
            "/graphql/",
            {
                "query": self.MUTATION,
                "variables": {
                    "input": {
                        "communityChannels": ["GITHUB", "DISCORD"],
                        "skip": False,
                    }
                },
            },
            content_type="application/json",
            **make_auth_header(user),
        )

        assert response.status_code == 200
        data = response.json()
        assert "errors" not in data
        result = data["data"]["updateOnboardingChannels"]
        assert result["completedChannels"] is True
        assert result["hasCompletedOnboarding"] is True

        # Verify channels were saved
        profile = MarketingProfile.objects.get(user=user)
        assert profile.community_channels == ["github", "discord"]


class TestSkipOnboardingMutation:
    """Tests for skipOnboarding mutation."""

    MUTATION = """
        mutation {
            skipOnboarding {
                id
                completedWelcome
                completedRole
                completedCompany
                completedChannels
                hasCompletedOnboarding
            }
        }
    """

    def test_skips_all_steps(self, client, user):
        """Should mark all steps as completed."""
        response = client.post(
            "/graphql/",
            {"query": self.MUTATION},
            content_type="application/json",
            **make_auth_header(user),
        )

        assert response.status_code == 200
        data = response.json()
        assert "errors" not in data
        result = data["data"]["skipOnboarding"]
        assert result["completedWelcome"] is True
        assert result["completedRole"] is True
        assert result["completedCompany"] is True
        assert result["completedChannels"] is True
        assert result["hasCompletedOnboarding"] is True
