"""Role-based access mixins for SME-Hub views.

Composes the existing core mixins with SME-Hub specific role lists. Each gate
also enforces business/entrepreneur verification status where the underlying
PRD subprocess requires it (e.g. SP2 application gated on verified business).
"""
from __future__ import annotations

from django.contrib import messages
from django.shortcuts import redirect

from apps.core.permissions.mixins import RoleRequiredMixin
from apps.core.permissions.roles import UserRole

SME_ADMIN_ROLES: tuple[str, ...] = (
    UserRole.SYSTEM_ADMIN,
    UserRole.ADMIN,
    UserRole.SME_ADMIN,
)

SME_PROGRAMME_ROLES: tuple[str, ...] = (
    *SME_ADMIN_ROLES,
    UserRole.PROGRAMME_OFFICER,
)

SME_ENTREPRENEUR_ROLES: tuple[str, ...] = (UserRole.ENTREPRENEUR,)
SME_MENTOR_ROLES: tuple[str, ...] = (UserRole.MENTOR,)
SME_INVESTOR_ROLES: tuple[str, ...] = (UserRole.INVESTOR, UserRole.FUNDER)
SME_SERVICE_PROVIDER_ROLES: tuple[str, ...] = (UserRole.SERVICE_PROVIDER,)
SME_PARTNER_ROLES: tuple[str, ...] = (UserRole.PARTNER,)
SME_BUYER_ROLES: tuple[str, ...] = (UserRole.BUYER,)
SME_JUDGE_ROLES: tuple[str, ...] = (UserRole.JUDGE,)
# SP6 Monitoring, Learning & Impact actor — admins also retain access.
SME_MEL_OFFICER_ROLES: tuple[str, ...] = (
    *SME_ADMIN_ROLES,
    UserRole.MEL_OFFICER,
)


class SMEAdminRequired(RoleRequiredMixin):
    allowed_roles = SME_ADMIN_ROLES


class ProgrammeStaffRequired(RoleRequiredMixin):
    """Programme officers and admins. Used for SP2 management views."""

    allowed_roles = SME_PROGRAMME_ROLES


class EntrepreneurRequired(RoleRequiredMixin):
    allowed_roles = SME_ENTREPRENEUR_ROLES


class EntrepreneurVerifiedRequired(RoleRequiredMixin):
    """SP1 FRSME-OBR021 — only verified entrepreneurs may register a business.

    An entrepreneur whose profile is simply not verified *yet* gets a friendly
    redirect back to the SME dashboard instead of a bare 403 — the lockout is
    temporary and actionable, unlike a genuine role mismatch (which still 403s
    via ``RoleRequiredMixin``).
    """

    allowed_roles = SME_ENTREPRENEUR_ROLES

    def dispatch(self, request, *args, **kwargs):
        user = request.user
        if (
            user.is_authenticated
            and not user.is_superuser
            and getattr(user, "role", "") in self.allowed_roles
        ):
            from apps.smehub.onboarding.models import EntrepreneurProfile

            profile = (
                EntrepreneurProfile.objects.filter(user=user).only("verification_status").first()
            )
            if profile is None or profile.verification_status != EntrepreneurProfile.Status.VERIFIED:
                messages.warning(
                    request,
                    "Your entrepreneur profile is still pending verification — "
                    "business registration unlocks once an administrator verifies you.",
                )
                return redirect("smehub_onboarding:my_dashboard")
        return super().dispatch(request, *args, **kwargs)


class BusinessVerifiedRequired(RoleRequiredMixin):
    """SP2 FRSME-INC008 — only verified businesses may apply to programmes.

    As above: an entrepreneur whose business exists but is awaiting
    verification is redirected with guidance rather than shown a bare 403.
    """

    allowed_roles = SME_ENTREPRENEUR_ROLES
    business_url_kwarg = "business_id"

    def dispatch(self, request, *args, **kwargs):
        user = request.user
        business_id = kwargs.get(self.business_url_kwarg)
        if (
            business_id
            and user.is_authenticated
            and not user.is_superuser
            and getattr(user, "role", "") in self.allowed_roles
        ):
            from apps.smehub.onboarding.models import Business

            ok = Business.objects.filter(
                pk=business_id,
                entrepreneur__user=user,
                verification_status=Business.Status.VERIFIED,
            ).exists()
            if not ok:
                messages.warning(
                    request,
                    "This business must be verified by an administrator before "
                    "you can continue — check its status on your dashboard.",
                )
                return redirect("smehub_onboarding:my_dashboard")
        return super().dispatch(request, *args, **kwargs)


class MentorRequired(RoleRequiredMixin):
    allowed_roles = SME_MENTOR_ROLES


class JudgeRequired(RoleRequiredMixin):
    allowed_roles = SME_JUDGE_ROLES


class InvestorRequired(RoleRequiredMixin):
    allowed_roles = SME_INVESTOR_ROLES


class ServiceProviderRequired(RoleRequiredMixin):
    allowed_roles = SME_SERVICE_PROVIDER_ROLES


class PartnerRequired(RoleRequiredMixin):
    allowed_roles = SME_PARTNER_ROLES


class BuyerRequired(RoleRequiredMixin):
    allowed_roles = SME_BUYER_ROLES


class MELOfficerRequired(RoleRequiredMixin):
    """SP6 actor — M&E Officer (PRD Table 45). SME admins retain access."""

    allowed_roles = SME_MEL_OFFICER_ROLES


SME_EVALUATOR_ROLES: tuple[str, ...] = (
    *SME_ADMIN_ROLES,
    UserRole.JUDGE,
    UserRole.PROGRAMME_OFFICER,
    UserRole.REVIEWER,
)


class EvaluatorRequired(RoleRequiredMixin):
    """Phase 6.1 — innovation vetting evaluator (judge / reviewer / admin)."""

    allowed_roles = SME_EVALUATOR_ROLES
