from typing import cast

from django.db import models
from django.template.defaultfilters import linebreaks_filter

from core.html import strip_html
from users.models import Follow, FollowStates, Identity


class IdentityService:
    """
    High-level helper methods for doing things to identities
    """

    def __init__(self, identity: Identity):
        self.identity = identity

    def following(self) -> models.QuerySet[Identity]:
        return (
            Identity.objects.filter(inbound_follows__source=self.identity)
            .not_deleted()
            .order_by("username")
            .select_related("domain")
        )

    def followers(self) -> models.QuerySet[Identity]:
        return (
            Identity.objects.filter(outbound_follows__target=self.identity)
            .not_deleted()
            .order_by("username")
            .select_related("domain")
        )

    def follow_from(self, from_identity: Identity) -> Follow:
        """
        Follows a user (or does nothing if already followed).
        Returns the follow.
        """
        existing_follow = Follow.maybe_get(from_identity, self.identity)
        if not existing_follow:
            Follow.create_local(from_identity, self.identity)
        elif existing_follow.state not in FollowStates.group_active():
            existing_follow.transition_perform(FollowStates.unrequested)
        return cast(Follow, existing_follow)

    def unfollow_from(self, from_identity: Identity):
        """
        Unfollows a user (or does nothing if not followed).
        """
        existing_follow = Follow.maybe_get(from_identity, self.identity)
        if existing_follow:
            existing_follow.transition_perform(FollowStates.undone)

    def mastodon_json_relationship(self, from_identity: Identity):
        """
        Returns a Relationship object for the from_identity's relationship
        with this identity.
        """
        return {
            "id": self.identity.pk,
            "following": self.identity.inbound_follows.filter(
                source=from_identity,
                state__in=FollowStates.group_active(),
            ).exists(),
            "followed_by": self.identity.outbound_follows.filter(
                target=from_identity,
                state__in=FollowStates.group_active(),
            ).exists(),
            "showing_reblogs": True,
            "notifying": False,
            "blocking": False,
            "blocked_by": False,
            "muting": False,
            "muting_notifications": False,
            "requested": False,
            "domain_blocking": False,
            "endorsed": False,
            "note": "",
        }

    def set_summary(self, summary: str):
        """
        Safely sets a summary and turns linebreaks into HTML
        """
        if summary:
            self.identity.summary = linebreaks_filter(strip_html(summary))
        else:
            self.identity.summary = None
        self.identity.save()
