"""Signal handlers for the Tenants app.

When a Tenant's plan FK changes, the handler syncs the corresponding
TenantSubscription row and dispatches a ``subscription.plan_changed`` event.
"""

from __future__ import annotations

import logging

from django.db.models.signals import post_save
from django.dispatch import receiver

from simorgh.apps.events.bus import dispatch
from simorgh.apps.tenants.models import Tenant

logger = logging.getLogger(__name__)


@receiver(post_save, sender=Tenant)
def _sync_tenant_subscription_on_plan_change(
    sender: type[Tenant],
    instance: Tenant,
    created: bool,
    raw: bool,
    **kwargs: object,
) -> None:
    """Sync TenantSubscription when Tenant.plan is set or changed.

    - If plan is None → no-op (keep existing subscription, if any).
    - If plan is set and no subscription exists → create one (active).
    - If plan changed → update subscription and dispatch event.
    """
    if raw:
        return  # Skip during fixture loading (loaddata).

    if instance.plan_id is None:
        return  # No plan assigned — nothing to sync.

    from simorgh.apps.subscription.models import (
        PlatformPlan,
        SubscriptionStatus,
        TenantSubscription,
    )

    sub = TenantSubscription.objects.filter(tenant=instance).select_related("plan").first()

    # Collect old code for event payload.
    old_plan_code = sub.plan.code if sub else instance.plan_ref or ""

    if sub is None:
        # Create a new subscription row.
        TenantSubscription.objects.create(
            tenant=instance,
            plan=instance.plan,
            status=SubscriptionStatus.ACTIVE,
        )
        logger.info(
            "TenantSubscription created for tenant=%s plan=%s",
            instance.slug,
            instance.plan.code,
        )
    elif sub.plan_id != instance.plan_id:
        old_code = sub.plan.code
        sub.plan = instance.plan
        sub.status = SubscriptionStatus.ACTIVE
        sub.save(update_fields=["plan", "status", "updated_at"])
        old_plan_code = old_code
    else:
        return  # No change.

    # Dispatch event via the platform Event Bus.
    dispatch(
        "subscription.plan_changed",
        payload={
            "tenant_id": str(instance.pk),
            "old_plan_code": old_plan_code,
            "new_plan_code": instance.plan.code,
            "actor_id": "system",
        },
    )
