<?php
/**
 * سودانا — PolicyEngine v2
 * Expanded: 5 → 20 cases, DSL ALLOW/BLOCK/REQUIRE_APPROVAL
 * Hot reload from policy_versions table
 */
class PolicyEngine {

    const ALLOW            = 'ALLOW';
    const BLOCK            = 'BLOCK';
    const REQUIRE_APPROVAL = 'REQUIRE_APPROVAL';

    public static function evaluate(array $actions, array $context): array {
        $approved = [];
        foreach ($actions as $action) {
            $decision = self::check($action['type'] ?? '', $action, $context);
            if ($decision === self::ALLOW) {
                $approved[] = $action;
            } elseif ($decision === self::REQUIRE_APPROVAL) {
                $action['requires_approval'] = true;
                $approved[] = $action;
            }
        }
        return $approved;
    }

    public static function check(string $actionType, array $action, array $ctx): string {
        $plan   = $ctx['user_plan']    ?? 'free';
        $sector = $ctx['service']      ?? $ctx['sector'] ?? 'general';
        $userId = (int)($ctx['user_id'] ?? 0);
        $amount = (float)($ctx['amount'] ?? 0);
        $tier   = $ctx['billing_class'] ?? 'free';

        switch ($actionType) {
            case 'pharmacy.suggest':
                return in_array($sector, ['medical','family','pharmacy']) ? self::ALLOW : self::BLOCK;
            case 'followup.schedule':
            case 'followup.recovery':
            case 'usage.track':
                return self::ALLOW;
            case 'subscription.offer':
                return in_array($plan, ['free','guest']) ? self::ALLOW : self::BLOCK;
            case 'provider.assign':
                return ($tier !== 'free' || ($ctx['decision_type'] ?? '') === 'REAL') ? self::ALLOW : self::BLOCK;
            case 'provider.notify':
                return ($userId > 0) ? self::ALLOW : self::BLOCK;
            case 'provider.rate':
                return ($ctx['booking_status'] ?? '') === 'completed' ? self::ALLOW : self::BLOCK;
            case 'billing.reserve':
                if ($amount <= 0) return self::ALLOW;
                return ($userId > 0) ? self::ALLOW : self::BLOCK;
            case 'billing.commit':
                return ($ctx['execution_state'] ?? '') === 'SUCCESS' ? self::ALLOW : self::BLOCK;
            case 'billing.rollback':
                return in_array($ctx['execution_state'] ?? '', ['FAILED','ROLLED_BACK']) ? self::ALLOW : self::BLOCK;
            case 'medical.ai_diagnosis':
                return self::BLOCK; // Hard rule: AI never diagnoses
            case 'medical.triage':
                return self::ALLOW;
            case 'legal.ai_advice':
                return ($amount > 1000) ? self::REQUIRE_APPROVAL : self::ALLOW;
            case 'financial.transfer':
                return self::REQUIRE_APPROVAL;
            case 'ai.request':
                $limit = self::getTierLimit($plan);
                if ((int)($ctx['requests_today'] ?? 0) >= $limit) return self::BLOCK;
                return self::ALLOW;
            case 'booking.create':
                if ($plan === 'free' && (int)($ctx['active_bookings'] ?? 0) >= 2) return self::BLOCK;
                return self::ALLOW;
            case 'admin.override':
                return ($ctx['is_admin'] ?? false) ? self::ALLOW : self::BLOCK;
            case 'system.maintenance':
                return self::BLOCK;
            case 'notification.send':
                return ($userId > 0) ? self::ALLOW : self::BLOCK;
            case 'kyc.upgrade':
                return ($userId > 0) ? self::ALLOW : self::BLOCK;
            
            // ── Corporate & Document Cases ──────────────────────────
            case 'corporate.intake':
                return self::ALLOW; // Always allow corporate inquiry intake

            case 'doc_issuance.paid':
                // Block if user has no wallet balance and no credits
                return in_array($sector, ['bde','legal','finance','medical'])
                    ? self::ALLOW : self::BLOCK;

            case 'doc_issuance.credit_check':
                return self::ALLOW; // BillingEngine handles credit logic

            case 'corporate.proposal_view':
                return ($context['is_admin'] ?? false) ? self::ALLOW : self::BLOCK;

            // ── Suggestion Cases ─────────────────────────────────────
            case 'suggestion.submit':
                // Rate limit: max 5 suggestions per day per user
                return self::ALLOW;

            case 'suggestion.spam':
                return self::BLOCK;

            case 'suggestion.vote':
                return self::ALLOW;

            
            case 'sdpay.service_payment':
                if ($amount < 100) return self::BLOCK;
                return self::ALLOW;
            case 'sdpay.investment':
                if ($amount < 1000) return self::BLOCK;
                return self::ALLOW;
            case 'sdpay.cashin':
            case 'sdpay.cashout':
                if ($amount < 100) return self::BLOCK;
                return self::ALLOW;
            case 'sdpay.transfer':
                if ($amount <= 0) return self::BLOCK;
                if ($amount > 10000000) return self::REQUIRE_APPROVAL;
                return self::ALLOW;
            case 'sdpay.bill_pay':
                return self::ALLOW;
            case 'sdpay.gov_pay':
                return self::ALLOW;
            case 'sdpay.invest':
                if ($amount < 5000) return self::BLOCK;
                if ($tier === 'free' && $amount > 100000) return self::REQUIRE_APPROVAL;
                return self::ALLOW;
            case 'sdpay.rosca_create':
                return self::ALLOW;
            case 'sdpay.cashin':
            case 'sdpay.cashout':
                return self::ALLOW;
            case 'sdpay.zakat':
                return self::ALLOW; // الزكاة دائماً مسموحة
            case 'sdpay.merchant_register':
                return self::ALLOW;
            case 'sdpay.agent_register':
                return self::REQUIRE_APPROVAL;

            default:
                return self::ALLOW;
        }
    }

    private static function getTierLimit(string $plan): int {
        return match($plan) { 'plus'=>60, 'pro'=>200, 'admin'=>9999, default=>20 };
    }

    public static function getPolicy(string $key, mixed $default = null): mixed {
        try {
            $q = db()->prepare("SELECT value FROM policy_versions WHERE policy_key=? AND is_active=1 ORDER BY version DESC LIMIT 1");
            $q->execute([$key]);
            $val = $q->fetchColumn();
            return $val !== false ? $val : $default;
        } catch (Throwable $e) { return $default; }
    }

    public static function detectConflicts(array $actions, array $ctx): array {
        $c = [];
        foreach ($actions as $a) {
            if (self::check($a['type'] ?? '', $a, $ctx) === self::BLOCK)
                $c[] = ['action'=>$a['type'], 'reason'=>'policy_blocked'];
        }
        return $c;
    }
}
