from rest_framework.permissions import BasePermission


# Maps each APIView to the permission required by an Accountant.
#
# GET = view permission
# POST/PUT/PATCH/DELETE = corresponding action permission

VIEW_PERMISSIONS = {
    # Dashboard
    "DashboardAPIView": {
        "GET": "dashboard_view",
    },

    # Business
    "BusinessListCreateAPIView": {
        "GET": "business_view",
        "POST": "business_add",
    },
    "BusinessDetailAPIView": {
        "GET": "business_view",
        "PUT": "business_edit",
        "PATCH": "business_edit",
        "DELETE": "business_delete",
    },
    "BusinessDocumentCreateAPIView": "business_edit",
    "BusinessDocumentListAPIView": "business_view",
    "BusinessInvestorsAPIView": "business_view",

    # Investor
    "InvestorListCreateAPIView": {
        "GET": "investor_view",
        "POST": "investor_add",
    },
    "InvestorDetailAPIView": {
        "GET": "investor_view",
        "PUT": "investor_edit",
        "PATCH": "investor_edit",
        "DELETE": "investor_delete",
    },
    "InvestorPortfolioAPIView": "investor_view",
    "InvestorDocumentListAPIView": "investor_view",

    # Schemes
    "SchemeListCreateAPIView": {
        "GET": "scheme_view",
        "POST": "scheme_add",
    },
    "SchemeDetailAPIView": {
        "GET": "scheme_view",
        "PUT": "scheme_edit",
        "PATCH": "scheme_edit",
        "DELETE": "scheme_delete",
    },

    # Kuber -> Business Investment
    "KuberBusinessInvestmentListCreateAPIView": {
        "GET": "kuber_investment_view",
        "POST": "kuber_investment_add",
    },
    "KuberBusinessInvestmentDetailAPIView": {
        "GET": "kuber_investment_view",
        "PUT": "kuber_investment_edit",
        "PATCH": "kuber_investment_edit",
        "DELETE": "kuber_investment_delete",
    },

    # Investor Investment
    "InvestmentListCreateAPIView": {
        "GET": "investment_view",
        "POST": "investment_add",
    },
    "InvestmentDetailAPIView": {
        "GET": "investment_view",
        "PUT": "investment_edit",
        "PATCH": "investment_edit",
        "DELETE": "investment_delete",
    },

    # Balance Sheets
    "BalanceSheetListCreateAPIView": {
        "GET": "balance_sheet_view",
        "POST": "balance_sheet_upload",
    },
    "BalanceSheetDetailAPIView": {
        "GET": "balance_sheet_view",
        "PUT": "balance_sheet_edit",
        "PATCH": "balance_sheet_edit",
        "DELETE": "balance_sheet_delete",
    },

    # Daily Financial Statements / P&L
    "DailyFinancialStatementListCreateAPIView": {
        "GET": "financial_statement_view",
        "POST": "financial_statement_add",
    },
    "DailyFinancialStatementDetailAPIView": {
        "GET": "financial_statement_view",
        "PUT": "financial_statement_edit",
        "PATCH": "financial_statement_edit",
        "DELETE": "financial_statement_delete",
    },

    # Ledger
    "LedgerListAPIView": "ledger_view",
    "GenerateDailyLedgerAPIView": "ledger_generate",

    # Payouts
    "PayoutListCreateAPIView": {
        "GET": "payout_view",
        "POST": "payout_create",
    },

    # Certificates
    "CertificateListCreateAPIView": {
        "GET": "certificate_view",
        "POST": "certificate_generate",
    },
    "CertificateDetailAPIView": {
        "GET": "certificate_view",
        "PUT": "certificate_generate",
        "PATCH": "certificate_generate",
        "DELETE": "certificate_generate",
    },
    "CertificateAttachmentDeleteAPIView": "certificate_generate",

    # Platinum recurring contribution
    "RecurringContributionListCreateAPIView": {
        "GET": "investment_view",
        "POST": "investment_edit",
    },
    "RecurringContributionDetailAPIView": {
        "GET": "investment_view",
        "PUT": "investment_edit",
        "PATCH": "investment_edit",
        "DELETE": "investment_edit",
    },

    # Audit / Restore
    "AuditLogListAPIView": "audit_view",
    "RestoreBinAPIView": "restore",
    "RestoreItemAPIView": "restore",

    # Exports
    "ExportLedgerAPIView": "ledger_view",
    "ExportInvestmentsAPIView": "investment_view",
}


def has_accountant_permission(user, permission_key):
    """
    Check whether the logged-in user has a specific Accountant permission.
    """

    if not user or not user.is_authenticated or not user.is_active:
        return False

    # Admin / Superuser / Staff can access everything.
    if (
        user.is_superuser
        or user.is_staff
        or user.role == "ADMIN"
    ):
        return True

    # Only Accountant users continue below.
    if user.role != "ACCOUNTANT":
        return False

    accountant_permissions = getattr(
        user,
        "accountant_permissions",
        None,
    )

    permissions = getattr(
        accountant_permissions,
        "permissions",
        {},
    ) or {}

    # Dashboard can be opened by an Accountant.
    if permission_key == "dashboard_view":
        return True

    return bool(
        permissions.get(permission_key, False)
    )


class IsAdmin(BasePermission):
    """
    Admin + Accountant permission-aware permission class.
    """

    message = "You do not have permission to perform this action."

    def has_permission(self, request, view):

        user = request.user

        # Authentication check
        if (
            not user
            or not user.is_authenticated
            or not user.is_active
        ):
            return False

        # Admin access
        if (
            user.is_superuser
            or user.is_staff
            or user.role == "ADMIN"
        ):
            return True

        # Accountant access
        if user.role == "ACCOUNTANT":

            view_name = view.__class__.__name__

            required_permission = VIEW_PERMISSIONS.get(
                view_name
            )

            # Endpoint not registered in permission map.
            if not required_permission:
                return False

            # Some endpoints have different permissions
            # depending on HTTP method.
            if isinstance(required_permission, dict):
                required_permission = required_permission.get(
                    request.method
                )

            if not required_permission:
                return False

            return has_accountant_permission(
                user,
                required_permission,
            )

        # Everyone else denied.
        return False