<?php
/**
 * سودانا — PricingEngine v1
 * محرك الأسعار — التحكم الكامل من لوحة الإدارة
 * Rate: 1 USD = X SDG (من platform_settings)
 */
class PricingEngine {

    const CACHE_TTL  = 300; // 5 دقائق
    const CACHE_KEY  = 'sudanna_pricing_v1';

    private static ?array $_cache = null;

    // ── getAll(): يُعيد كل الأسعار (cache أو DB) ───────────────
    public static function getAll(): array {
        if (self::$_cache !== null) return self::$_cache;

        // Try file cache
        $cacheFile = sys_get_temp_dir() . '/sudanna_pricing.json';
        if (file_exists($cacheFile) && (time() - filemtime($cacheFile)) < self::CACHE_TTL) {
            $cached = json_decode(file_get_contents($cacheFile), true);
            if ($cached) {
                self::$_cache = $cached;
                return $cached;
            }
        }

        $data = self::buildFromDB();
        self::$_cache = $data;

        // Write cache
        @file_put_contents($cacheFile, json_encode($data));
        return $data;
    }

    // ── buildFromDB(): يبني الأسعار من قاعدة البيانات ─────────
    private static function buildFromDB(): array {
        try {
            $settings = db()->query(
                "SELECT setting_key, value FROM platform_settings WHERE is_editable=1"
            )->fetchAll(PDO::FETCH_KEY_PAIR);
        } catch (Throwable $e) {
            // Fallback to config constants if DB not ready
            return self::getDefaults();
        }

        $rate = (float)($settings['usd_to_sdg_rate'] ?? USD_TO_SDG_RATE);

        // Plans
        $plusSDG = (int)($settings['sub_plus_override'] ?? 1)
            ? (int)($settings['sub_plus_price_sdg']  ?? SUB_PLUS_PRICE_SDG)
            : (int)round((float)($settings['sub_plus_base_usd'] ?? 5.00) * $rate);

        $proSDG  = (int)($settings['sub_pro_override'] ?? 1)
            ? (int)($settings['sub_pro_price_sdg']   ?? SUB_PRO_PRICE_SDG)
            : (int)round((float)($settings['sub_pro_base_usd']  ?? 12.20) * $rate);

        // Corporate packages (always calculated from USD)
        $starterSDG  = (int)round((float)($settings['corp_starter_base_usd']  ?? CORP_STARTER_USD)  * $rate);
        $businessSDG = (int)round((float)($settings['corp_business_base_usd'] ?? CORP_BUSINESS_USD) * $rate);
        $scaleSDG    = (int)round((float)($settings['corp_scale_base_usd']    ?? CORP_SCALE_USD)    * $rate);

        // Document prices
        $docs = [];
        try {
            $dpRows = db()->query(
                "SELECT doc_type, price_free_sdg, price_plus_sdg, price_pro_sdg FROM document_prices WHERE is_active=1"
            )->fetchAll();
            foreach ($dpRows as $row) {
                $docs[$row['doc_type']] = [
                    'free' => (int)$row['price_free_sdg'],
                    'plus' => (int)$row['price_plus_sdg'],
                    'pro'  => (int)$row['price_pro_sdg'],
                ];
            }
        } catch (Throwable $e) {
            $docs = self::getDefaultDocPrices();
        }

        return [
            'rate'       => $rate,
            'updated_at' => date('Y-m-d H:i:s'),
            'plans' => [
                'free' => [
                    'sdg' => 0,
                    'ai_day'         => (int)($settings['ai_daily_limit_free']  ?? (defined('AI_DAILY_LIMIT_FREE') ? AI_DAILY_LIMIT_FREE : 20)),
                    'bookings_day'   => (int)($settings['booking_limit_free']   ?? (defined('BOOKING_DAILY_LIMIT_FREE') ? BOOKING_DAILY_LIMIT_FREE : 2)),
                    'doc_credit_sdg' => 0,
                ],
                'plus' => [
                    'sdg' => $plusSDG,
                    'ai_day'         => (int)($settings['ai_daily_limit_plus']  ?? (defined('AI_DAILY_LIMIT_PLUS') ? AI_DAILY_LIMIT_PLUS : 60)),
                    'bookings_day'   => (int)($settings['booking_limit_plus']   ?? (defined('BOOKING_DAILY_LIMIT_PLUS') ? BOOKING_DAILY_LIMIT_PLUS : 5)),
                    'doc_credit_sdg' => (int)($settings['credit_plus_sdg'] ?? (defined('SUB_PLUS_CREDIT_SDG') ? SUB_PLUS_CREDIT_SDG : 15000)),
                ],
                'pro' => [
                    'sdg' => $proSDG,
                    'ai_day'         => (int)($settings['ai_daily_limit_pro']   ?? (defined('AI_DAILY_LIMIT_PRO') ? AI_DAILY_LIMIT_PRO : 200)),
                    'bookings_day'   => (int)($settings['booking_limit_pro']    ?? (defined('BOOKING_DAILY_LIMIT_PRO') ? BOOKING_DAILY_LIMIT_PRO : 20)),
                    'doc_credit_sdg' => (int)($settings['credit_pro_sdg'] ?? (defined('SUB_PRO_CREDIT_SDG') ? SUB_PRO_CREDIT_SDG : 50000)),
                ],
            ],
            'documents'  => $docs ?: self::getDefaultDocPrices(),
            'corporate'  => [
                'starter'  => [
                    'usd' => (int)($settings['corp_starter_base_usd']  ?? CORP_STARTER_USD),
                    'sdg' => $starterSDG,
                    'users' => 50,
                ],
                'business' => [
                    'usd' => (int)($settings['corp_business_base_usd'] ?? CORP_BUSINESS_USD),
                    'sdg' => $businessSDG,
                    'users' => 200,
                ],
                'scale'    => [
                    'usd' => (int)($settings['corp_scale_base_usd']    ?? CORP_SCALE_USD),
                    'sdg' => $scaleSDG,
                    'users' => 1000,
                ],
            ],
            'commission' => (float)($settings['commission_rate'] ?? 0.10),
            'limits'     => [
                'free_daily_sdg'  => (int)($settings['pay_limit_free_daily_sdg']  ?? 20000),
                'plus_daily_sdg'  => (int)($settings['pay_limit_plus_daily_sdg']  ?? 200000),
                'monthly_max_sdg' => (int)($settings['pay_limit_monthly_sdg']      ?? 1000000),
            ],
        ];
    }

    // ── flushCache(): يُفرِّغ cache عند تغيير الأسعار ───────────
    public static function flushCache(): void {
        self::$_cache = null;
        $cacheFile = sys_get_temp_dir() . '/sudanna_pricing.json';
        @unlink($cacheFile);
    }

    // ── getRate(): يُعيد سعر الصرف الفعّال ──────────────────────
    public static function getRate(): float {
        try {
            $rate = db()->query(
                "SELECT rate_usd_sdg FROM exchange_rates WHERE is_active=1 ORDER BY created_at DESC LIMIT 1"
            )->fetchColumn();
            return $rate ? (float)$rate : (defined('USD_TO_SDG_RATE') ? USD_TO_SDG_RATE : 4100);
        } catch (Throwable $e) {
            return defined('USD_TO_SDG_RATE') ? USD_TO_SDG_RATE : 4100;
        }
    }

    // ── toSDG(): يُحوِّل USD → SDG ──────────────────────────────
    public static function toSDG(float $usd): int {
        return (int)round($usd * self::getRate());
    }

    // ── updateRate(): يُحدِّث سعر الصرف مع سجل كامل ────────────
    public static function updateRate(float $newRate, int $adminId, string $note = ''): array {
        try {
            $currentRate = self::getRate();
            $changePct   = $currentRate > 0
                ? round((($newRate - $currentRate) / $currentRate) * 100, 2)
                : 0;

            // Deactivate current rate
            db()->exec("UPDATE exchange_rates SET is_active=0");

            // Insert new rate
            $st = db()->prepare(
                "INSERT INTO exchange_rates
                 (rate_usd_sdg, previous_rate, change_pct, source, note, set_by, is_active)
                 VALUES (?, ?, ?, 'manual', ?, ?, 1)"
            );
            $st->execute([$newRate, $currentRate, $changePct, $note, $adminId]);

            // Update platform_settings
            db()->prepare(
                "INSERT INTO platform_settings (setting_key, value, value_type, label_ar, category, unit)
                 VALUES ('usd_to_sdg_rate', ?, 'number', 'سعر صرف الدولار', 'exchange', 'SDG')
                 ON DUPLICATE KEY UPDATE value=VALUES(value), updated_by=?"
            )->execute([$newRate, $adminId]);

            self::flushCache();

            return [
                'ok'           => true,
                'new_rate'     => $newRate,
                'previous'     => $currentRate,
                'change_pct'   => $changePct,
                'alert'        => abs($changePct) >= 5,
                'preview'      => [
                    'plus_sdg'     => self::toSDG(5.00),
                    'pro_sdg'      => self::toSDG(12.20),
                    'starter_sdg'  => self::toSDG(CORP_STARTER_USD),
                    'business_sdg' => self::toSDG(CORP_BUSINESS_USD),
                ],
            ];
        } catch (Throwable $e) {
            return ['ok' => false, 'error' => $e->getMessage()];
        }
    }

    // ── updateSetting(): يُحدِّث إعداد واحد ─────────────────────
    public static function updateSetting(string $key, string $value, int $adminId): bool {
        try {
            db()->prepare(
                "UPDATE platform_settings SET value=?, updated_by=? WHERE setting_key=?"
            )->execute([$value, $adminId, $key]);
            self::flushCache();
            return true;
        } catch (Throwable $e) {
            error_log("[PricingEngine] updateSetting error: " . $e->getMessage());
            return false;
        }
    }

    // ── getDocumentPrice(): سعر وثيقة لمستخدم ───────────────────
    public static function getDocumentPrice(string $docType, string $planKey): int {
        $pricing = self::getAll();
        $docPrices = $pricing['documents'][$docType] ?? [];
        return (int)($docPrices[$planKey] ?? $docPrices['free'] ?? 0);
    }

    // ── checkDocumentCredit(): فحص رصيد الوثائق ─────────────────
    public static function checkDocumentCredit(int $userId, int $costSdg): array {
        try {
            $credit = db()->prepare(
                "SELECT id, remaining_sdg FROM subscription_credits
                 WHERE user_id=? AND period_month=MONTH(NOW()) AND period_year=YEAR(NOW())
                 LIMIT 1"
            );
            $credit->execute([$userId]);
            $row = $credit->fetch();

            if ($row && $row['remaining_sdg'] >= $costSdg) {
                return ['source' => 'credit', 'credit_id' => $row['id'], 'enough' => true];
            }
        } catch (Throwable $e) {}

        // Check wallet
        try {
            $wallet = db()->prepare("SELECT balance_sdg AS balance FROM wallet WHERE user_id=? LIMIT 1");
            $wallet->execute([$userId]);
            $balance = (float)($wallet->fetchColumn() ?? 0);

            if ($balance >= $costSdg) {
                return ['source' => 'wallet', 'balance' => $balance, 'enough' => true];
            }
        } catch (Throwable $e) {}

        return ['source' => 'none', 'enough' => false];
    }

    // ── getHistory(): سجل تغييرات سعر الصرف ─────────────────────
    public static function getHistory(int $limit = 30): array {
        try {
            $limit = max(1, min(500, $limit)); // safe bound for inline use
            $st = db()->prepare(
                "SELECT er.*, sm.name as set_by_name
                 FROM exchange_rates er
                 LEFT JOIN staff_members sm ON er.set_by = sm.id
                 ORDER BY er.created_at DESC LIMIT $limit"
            );
            $st->execute();
            return $st->fetchAll() ?: [];
        } catch (Throwable $e) {
            return [];
        }
    }

    // ── Defaults (fallback if DB not ready) ─────────────────────
    private static function getDefaults(): array {
        $rate = defined('USD_TO_SDG_RATE') ? USD_TO_SDG_RATE : 4100;
        return [
            'rate' => $rate, 'updated_at' => date('Y-m-d H:i:s'),
            'plans' => [
                'free' => ['sdg'=>0,'ai_day'=>20,'bookings_day'=>2,'doc_credit_sdg'=>0],
                'plus' => ['sdg'=>20000,'ai_day'=>60,'bookings_day'=>5,'doc_credit_sdg'=>15000],
                'pro'  => ['sdg'=>50000,'ai_day'=>200,'bookings_day'=>20,'doc_credit_sdg'=>50000],
            ],
            'documents' => self::getDefaultDocPrices(),
            'corporate' => [
                'starter'  => ['usd'=>99,  'sdg'=>99*$rate,  'users'=>50],
                'business' => ['usd'=>249, 'sdg'=>249*$rate, 'users'=>200],
                'scale'    => ['usd'=>599, 'sdg'=>599*$rate, 'users'=>1000],
            ],
            'commission' => 0.10,
            'limits' => ['free_daily_sdg'=>20000,'plus_daily_sdg'=>200000,'monthly_max_sdg'=>1000000],
        ];
    }

    private static function getDefaultDocPrices(): array {
        return [
            'ai_chat'       => ['free'=>500,  'plus'=>350,  'pro'=>0],
            'certificate'   => ['free'=>1000, 'plus'=>700,  'pro'=>500],
            'contract'      => ['free'=>5000, 'plus'=>3500, 'pro'=>2000],
            'proposal'      => ['free'=>5000, 'plus'=>3500, 'pro'=>2000],
            'business_plan' => ['free'=>10000,'plus'=>7500, 'pro'=>5000],
            'company_profile'=> ['free'=>7000,'plus'=>5000, 'pro'=>3500],
            'feasibility'   => ['free'=>15000,'plus'=>11000,'pro'=>8000],
            'legal_brief'   => ['free'=>8000, 'plus'=>6000, 'pro'=>4000],
            'translation'   => ['free'=>4000, 'plus'=>3000, 'pro'=>2000],
            'analysis'      => ['free'=>7000, 'plus'=>5000, 'pro'=>3500],
        ];
    }
// ── getSetting(): قراءة قيمة من platform_settings ──────────────
    public static function getSetting(string $key, $default = null) {
        // Priority: 1→ platform_settings DB  2→ PHP constant (UPPERCASE)  3→ default
        try {
            $st = db()->prepare("SELECT value, value_type FROM platform_settings WHERE setting_key=? LIMIT 1");
            $st->execute([$key]);
            $row = $st->fetch();
            if ($row) {
                return match($row['value_type']) {
                    'number'  => is_numeric($row['value']) ? $row['value']+0 : $default,
                    'boolean' => (bool)(int)$row['value'],
                    'json'    => json_decode($row['value'], true) ?: $default,
                    default   => $row['value'],
                };
            }
        } catch (Throwable $e) {}
        // Fallback: PHP constant (e.g. ai_daily_limit_free → AI_DAILY_LIMIT_FREE)
        $const = strtoupper($key);
        if (defined($const)) return constant($const);
        return $default;
    }

    // ── getImagePrices(): كل أسعار توليد الصور ─────────────────────
    public static function getImagePrices(): array {
        try {
            return db()->query(
                "SELECT * FROM image_prices WHERE is_active=1 ORDER BY id"
            )->fetchAll() ?: [];
        } catch (Throwable $e) { return []; }
    }

    // ── getVideoPrices(): كل أسعار توليد الفيديو ───────────────────
    public static function getVideoPrices(): array {
        try {
            return db()->query(
                "SELECT * FROM video_prices WHERE is_active=1 ORDER BY id"
            )->fetchAll() ?: [];
        } catch (Throwable $e) { return []; }
    }

    // ── getAILimit(): حد AI اليومي حسب الباقة ──────────────────────
    public static function getAILimit(string $plan): int {
        return (int)self::getSetting("ai_daily_limit_$plan", match($plan) {
            'plus' => 60, 'pro' => 200, 'corp' => 500, default => 20
        });
    }

    // ── getBookingLimit(): حد الحجوزات اليومي ──────────────────────
    public static function getBookingLimit(string $plan): int {
        return (int)self::getSetting("booking_limit_$plan", match($plan) {
            'plus' => 5, 'pro' => 20, 'corp' => 100, default => 2
        });
    }

    // ── auditPriceChange(): تسجيل تغيير سعر في ai_pricing_audit ────
    public static function auditPriceChange(string $entityType, string $entityKey,
                                            ?string $oldValue, ?string $newValue,
                                            int $adminId, string $reason = ''): void {
        try {
            db()->prepare(
                "INSERT INTO ai_pricing_audit
                 (entity_type, entity_key, old_value, new_value, changed_by, reason, created_at)
                 VALUES (?, ?, ?, ?, ?, ?, NOW())"
            )->execute([$entityType, $entityKey, $oldValue, $newValue, $adminId ?: null, $reason]);
        } catch (Throwable $e) {
            error_log("[PricingEngine::audit] " . $e->getMessage());
        }
    }

    /**
     * Monthly subscription price — from platform_settings, fallback to PAID_PRICE_SDG constant
     */
    public static function getSubscriptionPrice(): int {
        $fromSettings = (int)self::getSetting('subscription_price_sdg', 0);
        if ($fromSettings > 0) return $fromSettings;
        return defined('PAID_PRICE_SDG') ? (int)PAID_PRICE_SDG : 10000;
    }

}