<?php
/**
 * POST /api/tools/run.php
 * Phase 3 — Full Replace: Kernel + Estimation + Reservation + Execution
 *
 * ─── SCENARIOS ────────────────────────────────────────────────
 * 1. Request cost < threshold → direct execute via ToolsEngine (UsageMeter enforced internally)
 * 2. Request cost ≥ threshold → Estimate → confirm → execute
 * 3. POST { token:'EST_...' } → execute confirmed reservation
 *
 * ─── ENFORCEMENT ──────────────────────────────────────────────
 * - Auth required (Kernel::handle)
 * - Rate limit enforced (SecurityGate)
 * - AI calls ONLY via UsageMeter (no bypass)
 * - Documents ONLY via Reservation (≥ threshold)
 * - PricingEngine is the ONLY pricing source
 * - KernelExecutionToken enforced on TaskRunner
 */
require_once __DIR__ . '/../../config.php';
require_once __DIR__ . '/../../engine/Kernel.php';
require_once __DIR__ . '/../../engine/PricingEngine.php';
require_once __DIR__ . '/../../engine/TaskEstimator.php';
require_once __DIR__ . '/../../engine/BudgetGate.php';
require_once __DIR__ . '/../../engine/ReservationEngine.php';
require_once __DIR__ . '/../../engine/ToolsEngine.php';

// ── 1. Governance gate ───────────────────────────────────────────
// Every request goes through Kernel: auth + rate + trace_id + headers
$ctx  = Kernel::handle(['auth' => true, 'rate' => 'ai']);
$user = $ctx['user'];
$uid  = (int)$user['id'];
$plan = $user['plan_key'] ?? $user['subscription_tier'] ?? 'free';

// ── 2. Route: token present → execute reservation ────────────────
$body = Kernel::jsonBody();

if (!empty($body['token'])) {
    // Scenario 3: User confirmed estimation → execute
    Kernel::executeWithReservation($body['token']);
    // ^— exits here (calls Kernel::respond internally)
}

// ── 3. Validate new request ──────────────────────────────────────
$type   = preg_replace('/[^a-z_]/', '', $body['type'] ?? '');
$input  = mb_substr(trim($body['input'] ?? $body['query'] ?? ''), 0, 1000);
$sector = preg_replace('/[^a-z]/', '', $body['sector'] ?? 'general');

$allowed = ['document', 'code', 'analysis', 'export_pdf'];
if (!$type || !in_array($type, $allowed)) {
    Kernel::fail('invalid_type', 'النوع غير صحيح. المقبول: ' . implode(', ', $allowed), 422,
                 ['allowed' => $allowed]);
}
if (!$input) {
    Kernel::fail('empty_input', 'الوصف مطلوب', 422);
}

// ── 4. Get price from PricingEngine (ONLY source) ────────────────
// document subtype derived from sector; code/analysis have no price yet
// docSubtype must align with TaskEstimator keyword detection
// (same map used in prompt building above)
$docSubtype = match($type) {
    'document' => match($sector) {
        'legal', 'law' => 'contract',      // keywords: عقد, اتفاقية
        'business'     => 'business_plan', // keywords: خطة أعمال
        'education',
        'medical'      => 'report',        // keywords: تقرير
        default        => 'contract',
    },
    default => null,
};
$unitPriceSdg = $docSubtype
    ? PricingEngine::getDocumentPrice($docSubtype, $plan)
    : 0;

// ── 5. Threshold check (from platform_settings) ──────────────────
$threshold = (int)PricingEngine::getSetting('estimation_threshold_sdg', 3000);

if ($unitPriceSdg >= $threshold) {
    // Scenario 2: High-cost request → full Estimation → Reservation flow

    // Build estimation prompt with keywords TaskEstimator RuleParser can detect
    // Map sector → Arabic document keyword for reliable rule detection
    $_doc_keyword = match($sector) {
        'legal', 'law'   => 'عقد',
        'business'       => 'خطة أعمال',
        'education'      => 'تقرير',
        'medical'        => 'تقرير',
        default          => 'عقد',
    };
    $prompt = "أنشئ {$_doc_keyword} احترافياً لقطاع {$sector}: {$input}";
    unset($_doc_keyword);

    // Estimation + budget check + reservation hold (exits on reject)
    Kernel::estimateAndHold($user, $prompt);
    // ^— if approved: returns 200 with { action:'awaiting_confirmation', token, plan, ... }
    // ^— if insufficient funds: returns 402
    // ^— exits here via Kernel::respond()

} else {
    // Scenario 1: Low-cost request (code/analysis/export_pdf) — direct execute.
    // UsageMeter is enforced inside each ToolsEngine generate* method — NOT wrapped here.
    require_once __DIR__ . '/../../engine/BillingEngine.php';
    require_once __DIR__ . '/../../engine/Logger.php';

    // ── AI daily limit check (MUST come before any AI call) ───────
    $_tr_plan  = $user['plan_key'] ?? $user['subscription_tier'] ?? 'free';
    $_tr_limit = BillingEngine::checkAILimit($uid, $_tr_plan);
    if (!empty($_tr_limit['exceeded'])) {
        Kernel::fail(
            'daily_limit_exceeded',
            "تجاوزت حد {$_tr_limit['limit']} استدعاء/يوم",
            429,
            ['used' => $_tr_limit['used'], 'limit' => $_tr_limit['limit']]
        );
    }
    unset($_tr_plan, $_tr_limit);

    // ── Execute (UsageMeter enforced internally per method) ─────────
    $toolResult = ToolsEngine::run($type, $input, [
        'sector'  => $sector,
        'user_id' => $uid,
    ]);

    // ToolsEngine returns ok=false on budget/limit failure
    if (!($toolResult['ok'] ?? true) || !empty($toolResult['error'])) {
        $errKey   = $toolResult['error'] ?? 'execution_failed';
        $httpCode = match(true) {
            str_contains($errKey, 'limit')  => 429,
            str_contains($errKey, 'funds')  => 402,
            str_contains($errKey, 'blocked')=> 402,
            default                         => 500,
        };
        Kernel::fail($errKey, $toolResult['detail']['message'] ?? 'فشل التنفيذ', $httpCode);
    }

    Logger::info('tools_run_complete', [
        'type'   => $type,
        'sector' => $sector,
        'tokens' => $toolResult['tokens_used'] ?? 0,
    ]);

    Kernel::respond([
        'ok'           => true,
        'type'         => $type,
        'output'       => $toolResult['output'] ?? $toolResult['result'] ?? '',
        'file_url'     => $toolResult['file_url'] ?? null,
        'filename'     => $toolResult['filename'] ?? null,
        'sector'       => $sector,
        'charged_sdg'  => $toolResult['charged_sdg'] ?? 0,
        'wallet_after' => $toolResult['wallet_after'] ?? null,
        'tokens_used'  => $toolResult['tokens_used'] ?? 0,
        'trace_id'     => \Logger::traceId(),
    ]);
}
