<?php
/**
 * سودانا — AIEngine v1
 * Central engine for API requests, agent runs, and usage tracking.
 * All execution goes through: AIOrchestrator → ControlEngine → TaskEngine
 */
class AIEngine {

    // ── Free plan daily limits ────────────────────────────────────
    private const LIMIT_FREE = 50;
    private const LIMIT_PLUS = 500;
    private const LIMIT_PRO  = 5000;

    // ── Validate API key → returns user_id or null ─────────────────
    public static function validateKey(string $rawKey): ?array {
        if (!$rawKey || strlen($rawKey) < 20) return null;
        $hash = hash('sha256', $rawKey);
        try {
            $st = db()->prepare(
                "SELECT k.*, u.subscription_tier, u.plan_key
                 FROM ai_api_keys k
                 JOIN users u ON u.id = k.user_id
                 WHERE k.key_hash = ? AND k.status = 'active' LIMIT 1"
            );
            $st->execute([$hash]);
            $key = $st->fetch();
            if (!$key) return null;

            // Update last_used
            db()->prepare("UPDATE ai_api_keys SET last_used_at=NOW(), calls_today=calls_today+1, calls_total=calls_total+1 WHERE id=?")
                ->execute([$key['id']]);

            return $key;
        } catch (Throwable $e) {
            error_log("[AIEngine::validateKey] " . $e->getMessage());
            return null;
        }
    }

    // ── Check rate limit ──────────────────────────────────────────
    public static function checkLimit(int $userId, string $plan = 'free'): bool {
        $limit = match($plan) {
            'pro'        => self::LIMIT_PRO,
            'plus','paid'=> self::LIMIT_PLUS,
            default      => self::LIMIT_FREE,
        };
        try {
            $st = db()->prepare(
                "SELECT COUNT(*) FROM ai_usage
                 WHERE user_id=? AND DATE(created_at)=CURDATE()"
            );
            $st->execute([$userId]);
            return (int)$st->fetchColumn() < $limit;
        } catch (Throwable $e) {
            return true; // fail open — don't block on DB error
        }
    }

    // ── Log usage ─────────────────────────────────────────────────
    public static function logUsage(int $userId, string $type, array $meta = []): void {
        try {
            db()->prepare(
                "INSERT INTO ai_usage (user_id, api_key_id, agent_id, event_type, tokens_used, cost_usd, service, created_at)
                 VALUES (?, ?, ?, ?, ?, ?, ?, NOW())"
            )->execute([
                $userId,
                $meta['api_key_id'] ?? null,
                $meta['agent_id']   ?? null,
                $type,
                $meta['tokens']     ?? 0,
                $meta['cost_usd']   ?? 0,
                $meta['service']    ?? 'general',
            ]);
        } catch (Throwable $e) {
            error_log("[AIEngine::logUsage] " . $e->getMessage());
        }
    }

    // ── Generate API key ──────────────────────────────────────────
    public static function generateKey(int $userId, string $label = 'Default Key'): ?string {
        try {
            // Max 5 keys per user
            $count = db()->prepare("SELECT COUNT(*) FROM ai_api_keys WHERE user_id=? AND status='active'");
            $count->execute([$userId]);
            if ((int)$count->fetchColumn() >= 5) return null;

            $raw    = 'sdk_' . bin2hex(random_bytes(20));
            $hash   = hash('sha256', $raw);
            $prefix = substr($raw, 0, 12);

            db()->prepare(
                "INSERT INTO ai_api_keys (user_id, key_hash, key_prefix, label, status, created_at)
                 VALUES (?, ?, ?, ?, 'active', NOW())"
            )->execute([$userId, $hash, $prefix, $label]);

            return $raw; // shown ONCE — never stored plain
        } catch (Throwable $e) {
            error_log("[AIEngine::generateKey] " . $e->getMessage());
            return null;
        }
    }

    // ── Run agent ─────────────────────────────────────────────────
    public static function runAgent(int $agentId, int $userId, string $input): array {
        try {
            $agent = db()->prepare("SELECT * FROM ai_agents WHERE id=? AND user_id=? AND status='active' LIMIT 1");
            $agent->execute([$agentId, $userId]);
            $ag = $agent->fetch();
            if (!$ag) return ['error' => 'agent_not_found'];

            // Create run log
            $st = db()->prepare(
                "INSERT INTO ai_agent_runs (agent_id, user_id, input, status, created_at)
                 VALUES (?, ?, ?, 'running', NOW())"
            );
            $st->execute([$agentId, $userId, $input]);
            $runId = (int)db()->lastInsertId();

            $start = microtime(true);

            // Build prompt
            $prompt = $ag['prompt'] . "\n\nUser input: " . $input;

            // Use AIClient for generation
            require_once __DIR__ . '/AIClient.php';
            // UsageMeter wrap when userId provided
            if (!empty($userId)) {
                require_once __DIR__ . '/UsageMeter.php';
                $metered = UsageMeter::wrap(
                    (int)$userId,
                    'chat',
                    $ag['service'] ?? 'general',
                    fn() => AIClient::call($prompt, 'أنت مساعد ذكي متخصص. أجب بدقة وإيجاز.', 'fast', 300, 0.7, false),
                    ['skip_debit' => true]
                );
                $aiResult = $metered['ok'] ? $metered['result'] : null;
            } else {
                $aiResult = AIClient::call($prompt, 'أنت مساعد ذكي متخصص. أجب بدقة وإيجاز.', 'fast', 300, 0.7, false);
            }
            $output   = is_array($aiResult) ? ($aiResult['text'] ?? '') : (string)$aiResult;
            $latency  = round((microtime(true) - $start) * 1000);

            // Update run log (with real token usage)
            db()->prepare(
                "UPDATE ai_agent_runs SET output=?, status='done', latency_ms=?,
                  tokens_used=?, cost_usd=? WHERE id=?"
            )->execute([
                $output,
                $latency,
                (int)(($aiResult['tokens_in'] ?? 0) + ($aiResult['tokens_out'] ?? 0)),
                (float)($aiResult['cost_usd'] ?? 0),
                $runId,
            ]);

            // Update agent stats
            db()->prepare(
                "UPDATE ai_agents SET runs_total=runs_total+1, last_run_at=NOW() WHERE id=?"
            )->execute([$agentId]);

            // Log usage
            self::logUsage($userId, 'agent_run', ['agent_id'=>$agentId, 'service'=>$ag['service']]);

            // Emit event through EventBus
            EventBus::emit('ai_engine.used', [
                'user_id'  => $userId,
                'agent_id' => $agentId,
                'service'  => $ag['service'],
                'run_id'   => $runId,
            ]);

            return ['success'=>true, 'output'=>$output, 'run_id'=>$runId, 'latency_ms'=>$latency];

        } catch (Throwable $e) {
            error_log("[AIEngine::runAgent] " . $e->getMessage());
            return ['error' => 'execution_failed', 'message' => $e->getMessage()];
        }
    }

    // ── Process API chat request ──────────────────────────────────
    public static function processChat(string $question, array $keyData): array {
        $userId  = (int)$keyData['user_id'];
        $plan    = $keyData['plan_key'] ?? $keyData['subscription_tier'] ?? 'free';

        if (!self::checkLimit($userId, $plan)) {
            return ['error' => 'rate_limit_exceeded', 'message' => 'Daily limit reached. Upgrade your plan.'];
        }

        // Route through Gateway (reuses full inference pipeline)
        require_once __DIR__ . '/Gateway.php';
        $result = Gateway::handle(['question' => $question, 'user' => null, 'ip' => '0.0.0.0']);

        self::logUsage($userId, 'api_chat', [
            'api_key_id' => $keyData['id'],
            'service'    => $result['service'] ?? 'general',
        ]);

        EventBus::emit('ai_engine.used', [
            'user_id' => $userId,
            'service' => $result['service'] ?? 'general',
            'source'  => 'api',
        ]);

        return [
            'success' => true,
            'answer'  => $result['answer'] ?? '',
            'service' => $result['service'] ?? 'general',
            'source'  => $result['source']  ?? 'engine',
        ];
    }
}
