"""Delegation Engine services — business logic.

All write operations go through these functions; views must NOT call ORM
save/delete directly on Delegation models.
"""

from __future__ import annotations

from datetime import datetime

from django.db import transaction


def create_delegation_rule(
    *,
    tenant_id: int,
    organization_node_id: int,
    delegator_id: int,
    delegate_to_id: int,
    start_date: datetime,
    end_date: datetime,
    delegate_role_id: int | None = None,
    scope: str = "all",
    reason: str = "",
    is_active: bool = True,
    created_by_id: int | None = None,
) -> DelegationRule:
    from simorgh.apps.delegations.models import DelegationRule
    from simorgh.apps.events.bus import dispatch
    from simorgh.core.audit import record_service_event

    with transaction.atomic():
        rule = DelegationRule.objects.create(
            tenant_id=tenant_id,
            organization_node_id=organization_node_id,
            delegator_id=delegator_id,
            delegate_to_id=delegate_to_id,
            delegate_role_id=delegate_role_id,
            start_date=start_date,
            end_date=end_date,
            scope=scope,
            reason=reason,
            is_active=is_active,
            created_by_id=created_by_id,
        )

    record_service_event("delegations.rule.created", resource=rule, after={
        "delegator_id": delegator_id,
        "delegate_to_id": delegate_to_id,
        "is_active": is_active,
    })
    dispatch("delegation.created", {
        "delegation_rule_id": str(rule.public_id),
        "delegator_id": delegator_id,
        "delegate_to_id": delegate_to_id,
        "tenant_id": tenant_id,
    })
    return rule


def update_delegation_rule(
    rule: DelegationRule,
    *,
    delegate_to_id: int | None = None,
    delegate_role_id: int | None = ...,  # type: ignore[assignment]
    start_date: datetime | None = None,
    end_date: datetime | None = None,
    scope: str | None = None,
    reason: str | None = None,
    is_active: bool | None = None,
) -> DelegationRule:
    _SENTINEL = ...  # type: ignore[assignment]

    if delegate_to_id is not None:
        rule.delegate_to_id = delegate_to_id
    if delegate_role_id is not _SENTINEL:
        rule.delegate_role_id = delegate_role_id
    if start_date is not None:
        rule.start_date = start_date
    if end_date is not None:
        rule.end_date = end_date
    if scope is not None:
        rule.scope = scope
    if reason is not None:
        rule.reason = reason
    if is_active is not None:
        rule.is_active = is_active

    rule.save()
    return rule


def activate_delegation_rule(rule: DelegationRule) -> DelegationRule:
    from simorgh.apps.events.bus import dispatch
    from simorgh.core.audit import record_service_event

    if rule.is_active:
        return rule

    rule.is_active = True
    rule.save(update_fields=["is_active", "updated_at"])

    record_service_event("delegations.rule.activated", resource=rule)
    dispatch("delegation.activated", {
        "delegation_rule_id": str(rule.public_id),
        "delegator_id": rule.delegator_id,
        "delegate_to_id": rule.delegate_to_id,
        "tenant_id": rule.tenant_id,
    })
    return rule


def deactivate_delegation_rule(rule: DelegationRule) -> DelegationRule:
    from simorgh.apps.events.bus import dispatch
    from simorgh.core.audit import record_service_event

    if not rule.is_active:
        return rule

    rule.is_active = False
    rule.save(update_fields=["is_active", "updated_at"])

    record_service_event("delegations.rule.deactivated", resource=rule)
    dispatch("delegation.deactivated", {
        "delegation_rule_id": str(rule.public_id),
        "delegator_id": rule.delegator_id,
        "tenant_id": rule.tenant_id,
    })
    return rule


def delete_delegation_rule(rule: DelegationRule) -> None:
    from simorgh.apps.events.bus import dispatch
    from simorgh.core.audit import record_service_event

    rule_id = str(rule.public_id)
    delegator_id = rule.delegator_id
    tenant_id = rule.tenant_id

    record_service_event("delegations.rule.deleted", resource=rule)
    rule.delete()

    dispatch("delegation.deleted", {
        "delegation_rule_id": rule_id,
        "delegator_id": delegator_id,
        "tenant_id": tenant_id,
    })


def record_delegation_log(
    *,
    tenant_id: int,
    rule_id: int,
    action: str,
    content_type_id: int | None = None,
    object_id: int | None = None,
    metadata: dict | None = None,
) -> DelegationLog:
    from simorgh.apps.delegations.models import DelegationLog

    return DelegationLog.objects.create(
        tenant_id=tenant_id,
        rule_id=rule_id,
        action=action,
        content_type_id=content_type_id,
        object_id=object_id,
        metadata=metadata or {},
    )
