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

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

from accounts.models import Workspace, WorkspaceMembership
from core.graphql.enums import CampaignChannel, CampaignStatus

from .models import Campaign


@strawberry.type
class CampaignType:
    """GraphQL type for Campaign model."""

    id: ID
    name: str
    status: CampaignStatus
    channel: CampaignChannel
    send_at: str | None
    created_at: str
    updated_at: str
    workspace_id: ID

    @classmethod
    def from_model(cls, campaign: Campaign) -> "CampaignType":
        return cls(
            id=ID(str(campaign.pk)),
            name=campaign.name,
            status=CampaignStatus(campaign.status),
            channel=CampaignChannel(campaign.channel),
            send_at=campaign.send_at.isoformat() if campaign.send_at else None,
            created_at=campaign.created_at.isoformat() if campaign.created_at else "",
            updated_at=campaign.updated_at.isoformat() if campaign.updated_at else "",
            workspace_id=ID(str(campaign.workspace_id)),
        )


# Input types for mutations
@strawberry.input
class CreateCampaignInput:
    workspace_id: ID
    name: str
    channel: CampaignChannel = CampaignChannel.ANNOUNCEMENT
    status: CampaignStatus = CampaignStatus.DRAFT
    send_at: str | None = None


@strawberry.input
class UpdateCampaignInput:
    name: str | None = None
    status: CampaignStatus | None = None
    channel: CampaignChannel | None = None
    send_at: str | 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 CampaignsQuery:
    """Queries for campaigns app."""

    @strawberry.field
    def campaigns(
        self,
        info: Info,
        workspace_id: ID,
        status: CampaignStatus | None = None,
    ) -> list[CampaignType]:
        """Get all campaigns 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 []

        campaigns = Campaign.objects.filter(workspace_id=workspace_id)

        if status:
            campaigns = campaigns.filter(status=status.value)

        return [CampaignType.from_model(c) for c in campaigns.order_by("-created_at")]

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

        try:
            campaign = Campaign.objects.get(pk=id)
        except Campaign.DoesNotExist:
            return None

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

        return CampaignType.from_model(campaign)


@strawberry.type
class CampaignsMutation:
    """Mutations for campaigns app."""

    @strawberry.mutation
    def create_campaign(self, info: Info, input: CreateCampaignInput) -> CampaignType:
        """Create a new campaign."""
        workspace = check_workspace_access(info.context.user, input.workspace_id, ["owner", "admin", "member"])

        from datetime import datetime

        send_at = None
        if input.send_at:
            send_at = datetime.fromisoformat(input.send_at.replace("Z", "+00:00"))

        campaign = Campaign.objects.create(
            workspace=workspace,
            name=input.name,
            status=input.status.value,
            channel=input.channel.value,
            send_at=send_at,
        )
        return CampaignType.from_model(campaign)

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

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

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

        if input.name is not None:
            campaign.name = input.name
        if input.status is not None:
            campaign.status = input.status.value
        if input.channel is not None:
            campaign.channel = input.channel.value
        if input.send_at is not None:
            from datetime import datetime

            campaign.send_at = datetime.fromisoformat(input.send_at.replace("Z", "+00:00"))

        campaign.save()
        return CampaignType.from_model(campaign)

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

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

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

        campaign.delete()
        return True
