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

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

from accounts.models import Workspace, WorkspaceMembership

from .models import Rule


@strawberry.type
class RuleType:
    """GraphQL type for Rule model."""

    id: ID
    name: str
    description: str
    predicate: strawberry.scalars.JSON
    action: str
    action_params: strawberry.scalars.JSON
    priority: int
    is_enabled: bool
    created_at: str
    updated_at: str
    workspace_id: ID

    @classmethod
    def from_model(cls, rule: Rule) -> "RuleType":
        return cls(
            id=ID(str(rule.pk)),
            name=rule.name,
            description=rule.description or "",
            predicate=rule.predicate or {},
            action=rule.action,
            action_params=rule.action_params or {},
            priority=rule.priority,
            is_enabled=rule.is_enabled,
            created_at=rule.created_at.isoformat() if rule.created_at else "",
            updated_at=rule.updated_at.isoformat() if rule.updated_at else "",
            workspace_id=ID(str(rule.workspace_id)),
        )


# Input types for mutations
@strawberry.input
class CreateRuleInput:
    workspace_id: ID
    name: str
    action: str
    description: str | None = None
    predicate: strawberry.scalars.JSON | None = None
    action_params: strawberry.scalars.JSON | None = None
    priority: int = 0
    is_enabled: bool = True


@strawberry.input
class UpdateRuleInput:
    name: str | None = None
    description: str | None = None
    predicate: strawberry.scalars.JSON | None = None
    action: str | None = None
    action_params: strawberry.scalars.JSON | None = None
    priority: int | None = None
    is_enabled: bool | None = None


def check_workspace_access(user, workspace_id: ID, roles: list[str] | None = None) -> Workspace:
    """Check if user has access to workspace and return the workspace."""
    if not user or not user.is_authenticated:
        raise Exception("Authentication required") from None

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

    membership_filter = {"user": user, "workspace": workspace}
    if roles:
        membership_filter["role__in"] = roles

    if not WorkspaceMembership.objects.filter(**membership_filter).exists():
        raise Exception("Permission denied") from None

    return workspace


@strawberry.type
class RulesQuery:
    """Queries for rules app."""

    @strawberry.field
    def rules(
        self,
        info: Info,
        workspace_id: ID,
        is_enabled: bool | None = None,
    ) -> list[RuleType]:
        """Get all rules in a workspace."""
        user = info.context.user
        if not user or not user.is_authenticated:
            return []

        has_access = WorkspaceMembership.objects.filter(user=user, workspace_id=workspace_id).exists()
        if not has_access:
            return []

        rules = Rule.objects.filter(workspace_id=workspace_id)

        if is_enabled is not None:
            rules = rules.filter(is_enabled=is_enabled)

        return [RuleType.from_model(r) for r in rules.order_by("-priority", "id")]

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

        try:
            rule = Rule.objects.get(pk=id)
        except Rule.DoesNotExist:
            return None

        has_access = WorkspaceMembership.objects.filter(user=user, workspace=rule.workspace).exists()
        if not has_access:
            return None

        return RuleType.from_model(rule)


@strawberry.type
class RulesMutation:
    """Mutations for rules app."""

    @strawberry.mutation
    def create_rule(self, info: Info, input: CreateRuleInput) -> RuleType:
        """Create a new rule."""
        workspace = check_workspace_access(info.context.user, input.workspace_id, ["owner", "admin"])

        rule = Rule.objects.create(
            workspace=workspace,
            name=input.name,
            description=input.description or "",
            predicate=input.predicate or {},
            action=input.action,
            action_params=input.action_params or {},
            priority=input.priority,
            is_enabled=input.is_enabled,
        )
        return RuleType.from_model(rule)

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

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

        check_workspace_access(user, ID(str(rule.workspace_id)), ["owner", "admin"])

        if input.name is not None:
            rule.name = input.name
        if input.description is not None:
            rule.description = input.description
        if input.predicate is not None:
            rule.predicate = input.predicate
        if input.action is not None:
            rule.action = input.action
        if input.action_params is not None:
            rule.action_params = input.action_params
        if input.priority is not None:
            rule.priority = input.priority
        if input.is_enabled is not None:
            rule.is_enabled = input.is_enabled

        rule.save()
        return RuleType.from_model(rule)

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

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

        check_workspace_access(user, ID(str(rule.workspace_id)), ["owner", "admin"])

        rule.delete()
        return True
