"""GraphQL types, queries, and mutations for accounts app."""

from enum import Enum

import strawberry
from strawberry import ID
from strawberry.types import Info

from core.graphql.enums import MembershipRole

from . import services
from .models import (
    MarketingProfile,
    OnboardingProgress,
    Workspace,
    WorkspaceMembership,
)

# =============================================================================
# Onboarding Enums
# =============================================================================


@strawberry.enum
class Role(Enum):
    """User's professional role."""

    DEVREL = "devrel"
    COMMUNITY_MANAGER = "community_manager"
    DEVELOPER = "developer"
    OTHER = "other"


@strawberry.enum
class CompanySize(Enum):
    """Company size categories."""

    SOLO_INDIE = "solo_indie"
    STARTUP = "startup"
    MIDSIZE = "midsize"
    ENTERPRISE = "enterprise"


@strawberry.enum
class CommunityChannel(Enum):
    """Community channel platforms."""

    GITHUB = "github"
    DISCORD = "discord"
    SLACK = "slack"
    TWITTER = "twitter"
    LINKEDIN = "linkedin"
    MASTODON = "mastodon"
    DISCOURSE = "discourse"


# =============================================================================
# Onboarding Types
# =============================================================================


@strawberry.type
class OnboardingProgressType:
    """Tracks user's progress through the onboarding flow."""

    id: ID
    has_completed_onboarding: bool
    completed_welcome: bool
    completed_role: bool
    completed_company: bool
    completed_channels: bool

    @classmethod
    def from_model(cls, progress: OnboardingProgress) -> "OnboardingProgressType":
        return cls(
            id=ID(str(progress.id)),
            has_completed_onboarding=progress.has_completed_onboarding,
            completed_welcome=progress.completed_welcome,
            completed_role=progress.completed_role,
            completed_company=progress.completed_company,
            completed_channels=progress.completed_channels,
        )


@strawberry.type
class MarketingProfileType:
    """Marketing data collected during onboarding."""

    id: ID
    role: Role | None
    company_size: CompanySize | None
    community_channels: list[CommunityChannel]

    @classmethod
    def from_model(cls, profile: MarketingProfile) -> "MarketingProfileType":
        # Convert string role to enum
        role_enum = Role(profile.role) if profile.role else None
        # Convert string company_size to enum
        company_size_enum = CompanySize(profile.company_size) if profile.company_size else None
        # Convert list of strings to list of enums
        channels = [CommunityChannel(ch) for ch in (profile.community_channels or [])]

        return cls(
            id=ID(str(profile.id)),
            role=role_enum,
            company_size=company_size_enum,
            community_channels=channels,
        )


# =============================================================================
# Onboarding Input Types
# =============================================================================


@strawberry.input
class UpdateOnboardingRoleInput:
    """Input for updating onboarding role step."""

    role: Role | None = None
    skip: bool = False


@strawberry.input
class UpdateOnboardingCompanyInput:
    """Input for updating onboarding company step."""

    company_size: CompanySize | None = None
    skip: bool = False


@strawberry.input
class UpdateOnboardingChannelsInput:
    """Input for updating onboarding channels step."""

    community_channels: list[CommunityChannel] | None = None
    skip: bool = False


@strawberry.type
class WorkspaceType:
    """GraphQL type for Workspace model."""

    id: ID
    name: str
    slug: str
    created_at: str
    updated_at: str

    @strawberry.field
    def memberships(self, info: Info) -> list["WorkspaceMembershipType"]:
        """Get all memberships in this workspace."""
        ws = Workspace.objects.get(pk=self.id)
        return [WorkspaceMembershipType.from_model(m) for m in ws.memberships.all()]

    @classmethod
    def from_model(cls, ws: Workspace) -> "WorkspaceType":
        return cls(
            id=ID(str(ws.pk)),
            name=ws.name,
            slug=ws.slug,
            created_at=ws.created_at.isoformat() if ws.created_at else "",
            updated_at=ws.updated_at.isoformat() if ws.updated_at else "",
        )


@strawberry.type
class WorkspaceMembershipType:
    """GraphQL type for WorkspaceMembership model."""

    id: ID
    role: MembershipRole
    created_at: str
    updated_at: str
    user_id: ID
    workspace_id: ID

    @strawberry.field
    def workspace(self, info: Info) -> WorkspaceType:
        """Get the workspace for this membership."""
        membership = WorkspaceMembership.objects.select_related("workspace").get(pk=self.id)
        return WorkspaceType.from_model(membership.workspace)

    @classmethod
    def from_model(cls, membership: WorkspaceMembership) -> "WorkspaceMembershipType":
        return cls(
            id=ID(str(membership.pk)),
            role=MembershipRole(membership.role),
            created_at=membership.created_at.isoformat() if membership.created_at else "",
            updated_at=membership.updated_at.isoformat() if membership.updated_at else "",
            user_id=ID(str(membership.user_id)),
            workspace_id=ID(str(membership.workspace_id)),
        )


# Input types for mutations
@strawberry.input
class CreateWorkspaceInput:
    name: str
    slug: str


@strawberry.input
class UpdateWorkspaceInput:
    name: str | None = None
    slug: str | None = None


@strawberry.type
class AccountsQuery:
    """Queries for accounts app."""

    @strawberry.field
    def workspaces(self, info: Info) -> list[WorkspaceType]:
        """Get all workspaces the current user has access to."""
        user = info.context.user
        if not user or not user.is_authenticated:
            return []

        workspace_ids = WorkspaceMembership.objects.filter(user=user).values_list("workspace_id", flat=True)
        workspaces = Workspace.objects.filter(pk__in=workspace_ids)

        return [WorkspaceType.from_model(ws) for ws in workspaces]

    @strawberry.field
    def workspace(self, info: Info, id: ID) -> WorkspaceType | None:
        """Get a specific workspace by ID."""
        user = info.context.user
        if not user or not user.is_authenticated:
            return None

        try:
            ws = Workspace.objects.get(pk=id)
            # Check user has access
            has_access = WorkspaceMembership.objects.filter(user=user, workspace=ws).exists()
            if not has_access:
                return None
            return WorkspaceType.from_model(ws)
        except Workspace.DoesNotExist:
            return None

    @strawberry.field
    def onboarding_progress(self, info: Info) -> OnboardingProgressType | None:
        """Get the current user's onboarding progress."""
        user = info.context.user
        if not user or not user.is_authenticated:
            return None

        try:
            progress = OnboardingProgress.objects.get(user=user)
            return OnboardingProgressType.from_model(progress)
        except OnboardingProgress.DoesNotExist:
            return None

    @strawberry.field
    def marketing_profile(self, info: Info) -> MarketingProfileType | None:
        """Get the current user's marketing profile."""
        user = info.context.user
        if not user or not user.is_authenticated:
            return None

        try:
            profile = MarketingProfile.objects.get(user=user)
            return MarketingProfileType.from_model(profile)
        except MarketingProfile.DoesNotExist:
            return None


@strawberry.type
class AccountsMutation:
    """Mutations for accounts app."""

    @strawberry.mutation
    def create_workspace(self, info: Info, input: CreateWorkspaceInput) -> WorkspaceType:
        """Create a new workspace."""
        user = info.context.user
        if not user or not user.is_authenticated:
            raise Exception("Authentication required") from None

        if Workspace.objects.filter(slug=input.slug).exists():
            raise Exception("Workspace with this slug already exists") from None

        ws = Workspace.objects.create(name=input.name, slug=input.slug)

        # Add creator as owner
        WorkspaceMembership.objects.create(user=user, workspace=ws, role="owner")

        return WorkspaceType.from_model(ws)

    @strawberry.mutation
    def update_workspace(self, info: Info, id: ID, input: UpdateWorkspaceInput) -> WorkspaceType:
        """Update a workspace."""
        user = info.context.user
        if not user or not user.is_authenticated:
            raise Exception("Authentication required") from None

        try:
            ws = Workspace.objects.get(pk=id)
        except Workspace.DoesNotExist:
            raise Exception("Workspace not found") from None

        # Check user has admin access
        has_admin_access = WorkspaceMembership.objects.filter(
            user=user, workspace=ws, role__in=["owner", "admin"]
        ).exists()
        if not has_admin_access:
            raise Exception("Permission denied") from None

        if input.name is not None:
            ws.name = input.name
        if input.slug is not None:
            if Workspace.objects.filter(slug=input.slug).exclude(pk=id).exists():
                raise Exception("Workspace with this slug already exists") from None
            ws.slug = input.slug

        ws.save()
        return WorkspaceType.from_model(ws)

    @strawberry.mutation
    def delete_workspace(self, info: Info, id: ID) -> bool:
        """Delete a workspace."""
        user = info.context.user
        if not user or not user.is_authenticated:
            raise Exception("Authentication required") from None

        try:
            ws = Workspace.objects.get(pk=id)
        except Workspace.DoesNotExist:
            raise Exception("Workspace not found") from None

        # Check user has owner access
        has_owner_access = WorkspaceMembership.objects.filter(user=user, workspace=ws, role="owner").exists()
        if not has_owner_access:
            raise Exception("Permission denied") from None

        ws.delete()
        return True

    # =========================================================================
    # Onboarding Mutations
    # =========================================================================

    @strawberry.mutation
    def complete_welcome_step(self, info: Info) -> OnboardingProgressType:
        """
        Mark the welcome step as completed.

        Creates OnboardingProgress and MarketingProfile records if they don't exist.
        """
        user = info.context.user
        if not user or not user.is_authenticated:
            raise Exception("Authentication required") from None

        progress = services.complete_welcome_step(user=user)
        return OnboardingProgressType.from_model(progress)

    @strawberry.mutation
    def update_onboarding_role(self, info: Info, input: UpdateOnboardingRoleInput) -> OnboardingProgressType:
        """
        Update role selection and mark role step as completed.

        If skip is true, marks step complete without saving role.
        """
        user = info.context.user
        if not user or not user.is_authenticated:
            raise Exception("Authentication required") from None

        role_value = input.role.value if input.role else None
        progress = services.update_onboarding_role(
            user=user,
            role=role_value,
            skip=input.skip,
        )
        return OnboardingProgressType.from_model(progress)

    @strawberry.mutation
    def update_onboarding_company(self, info: Info, input: UpdateOnboardingCompanyInput) -> OnboardingProgressType:
        """
        Update company size selection and mark company step as completed.

        If skip is true, marks step complete without saving company size.
        """
        user = info.context.user
        if not user or not user.is_authenticated:
            raise Exception("Authentication required") from None

        company_size_value = input.company_size.value if input.company_size else None
        progress = services.update_onboarding_company(
            user=user,
            company_size=company_size_value,
            skip=input.skip,
        )
        return OnboardingProgressType.from_model(progress)

    @strawberry.mutation
    def update_onboarding_channels(self, info: Info, input: UpdateOnboardingChannelsInput) -> OnboardingProgressType:
        """
        Update channel interests and mark channels step as completed.

        If skip is true, marks step complete without saving channels.
        Also sets hasCompletedOnboarding to true (final step).
        """
        user = info.context.user
        if not user or not user.is_authenticated:
            raise Exception("Authentication required") from None

        channels_value = None
        if input.community_channels:
            channels_value = [ch.value for ch in input.community_channels]

        progress = services.update_onboarding_channels(
            user=user,
            community_channels=channels_value,
            skip=input.skip,
        )
        return OnboardingProgressType.from_model(progress)

    @strawberry.mutation
    def skip_onboarding(self, info: Info) -> OnboardingProgressType:
        """
        Skip all remaining onboarding steps and mark as completed.

        Useful for users who want to get to the product quickly.
        """
        user = info.context.user
        if not user or not user.is_authenticated:
            raise Exception("Authentication required") from None

        progress = services.skip_onboarding(user=user)
        return OnboardingProgressType.from_model(progress)
