"""Supported customer mutations. No RBAC decisions are made here."""
from contextlib import contextmanager

from django.core.exceptions import ValidationError
from django.db import transaction

from apps.organization.models import Company
from .models import Customer


_UNSET = object()


def _persisted(instance, model):
    if not isinstance(instance, model) or instance._state.adding or instance._state.db != "default":
        raise ValidationError(f"A persisted {model.__name__} is required.")
    return instance.pk


@contextmanager
def _locked_customer(customer):
    pk = _persisted(customer, Customer)
    with transaction.atomic():
        company_id = Customer.objects.values_list("company_id", flat=True).get(pk=pk)
        Company.objects.select_for_update().get(pk=company_id)
        yield Customer.objects.select_for_update().get(pk=pk)


def create_customer(*, company, customer_type, full_name="", organization_name="",
                    primary_mobile="", primary_email=""):
    _persisted(company, Company)
    customer = Customer(company=company, customer_type=customer_type, full_name=full_name,
                        organization_name=organization_name, primary_mobile=primary_mobile,
                        primary_email=primary_email)
    customer.save(force_insert=True)
    return customer


def update_customer(*, customer, full_name=_UNSET, organization_name=_UNSET,
                    primary_mobile=_UNSET, primary_email=_UNSET):
    changes = {name: value for name, value in (
        ("full_name", full_name), ("organization_name", organization_name),
        ("primary_mobile", primary_mobile), ("primary_email", primary_email),
    ) if value is not _UNSET}
    with _locked_customer(customer) as current:
        for name, value in changes.items():
            setattr(current, name, value)
        if changes:
            current.save(update_fields=changes)
        return current


def _set_active(customer, active):
    with _locked_customer(customer) as current:
        if active and not Company.objects.filter(pk=current.company_id, is_active=True).exists():
            raise ValidationError("Reactivation requires an active company.")
        if current.is_active != active:
            current.is_active = active
            current.save(update_fields=["is_active"])
        return current


def deactivate_customer(*, customer):
    return _set_active(customer, False)


def reactivate_customer(*, customer):
    return _set_active(customer, True)


# Public customer-domain API; implementation kept separate from frozen workflows.
from .detail_services import (  # noqa: E402
    create_customer_address, update_customer_address, set_primary_customer_address,
    deactivate_customer_address, reactivate_customer_address,
    create_customer_contact, update_customer_contact, set_primary_customer_contact,
    deactivate_customer_contact, reactivate_customer_contact,
)
