<?php
require_once __DIR__ . '/../../config.php';
require_once __DIR__ . '/../../engine/Kernel.php';

$ctx = Kernel::handle(['auth' => true, 'rate' => 'api']);
$u   = $ctx['user'];
if ($_SERVER['REQUEST_METHOD'] !== 'POST') Kernel::respond(['error'=>'method_not_allowed'],405);

// Feature flag check
try {
    $flag = db()->prepare("SELECT is_enabled FROM feature_flags WHERE flag_name='enable_booking' LIMIT 1");
    $flag->execute();
    if (!(int)($flag->fetchColumn())) {
        Kernel::respond(['error'=>'coming_soon','message'=>'الحجز متاح قريباً — تابعنا! 📅'],503);
    }
} catch (Throwable $e) {
    Kernel::respond(['error'=>'coming_soon','message'=>'الحجز متاح قريباً 📅'],503);
}

if (!check_rate_limit('booking_create_'.$u['id'], 5, 3600))
    Kernel::respond(['error'=>'rate_limit','message'=>'حاول بعد ساعة'],429);

$b           = json_decode(file_get_contents('php://input'), true) ?? [];
$provider_id = (int)($b['provider_id'] ?? 0);
$service_id  = isset($b['service_id']) ? (int)$b['service_id'] : null;
$date        = trim($b['booking_date'] ?? '');
$time        = trim($b['booking_time'] ?? '');
$notes       = mb_substr(trim($b['notes'] ?? ''), 0, 500);
// Telemedicine fields
$consultation_type = in_array($b['consultation_type'] ?? '', ['clinic','video','chat'])
                   ? $b['consultation_type'] : 'clinic';
$meeting_link = $consultation_type !== 'clinic'
              ? ('https://sudanna.ai/meet/' . bin2hex(random_bytes(8)))
              : null;

// ── FIX 4: ANTI-BYPASS — require valid flow session ───────────────
// Bookings must originate from StepController flow — no direct API bypass
$flow_session_id = trim($b['flow_session_id'] ?? '');
$bypass_allowed  = false;

if ($flow_session_id) {
    // Validate flow session: must be active, belong to this user, and be in booking step
    try {
        $fs = db()->prepare(
            "SELECT current_step, status, user_id, flow_id FROM flow_sessions
             WHERE session_id=? AND status='active' AND user_id=? LIMIT 1"
        );
        $fs->execute([$flow_session_id, $u['id']]);
        $session = $fs->fetch();

        if ($session && in_array($session['current_step'], ['booking','consultation','providers'])) {
            $bypass_allowed = true; // Valid flow session at correct step
        } elseif ($session) {
            Kernel::respond([
                'error'        => 'invalid_step',
                'message'      => 'الحجز يتطلب إكمال خطوات التقييم أولاً',
                'current_step' => $session['current_step'],
            ], 403);
        }
    } catch (Throwable $e) {
        // DB error — fail secure
        error_log('[booking/create] Flow validation DB error: ' . $e->getMessage());
        $bypass_allowed = false;
    }
}

if (!$bypass_allowed) {
    // Allow emergency bypass ONLY with explicit admin override token
    // Admin override requires server-side token — deprecated for Closed Beta
    // Use flow_session_id instead
    $bypass_allowed = false; // explicit: no bypass without valid flow session
}

if (!$bypass_allowed) {
    Kernel::respond([
        'error'   => 'flow_required',
        'message' => 'يجب البدء من خلال المساعد الذكي لإكمال الحجز',
        'hint'    => 'استخدم زر "استشارة طبية" أو "احجز الآن" في المساعد',
    ], 403);
}
// ── END FIX 4 ─────────────────────────────────────────────────────

// BRIDGE: Booking daily limit check — BEFORE any DB transaction
$_bk_plan  = $u['plan_key'] ?? $u['subscription_tier'] ?? 'free';
$_bk_limit = BillingEngine::checkBookingLimit((int)$u['id'], $_bk_plan);
if (!empty($_bk_limit['exceeded'])) {
    Kernel::respond([
        'error'   => 'booking_daily_limit',
        'message' => "تجاوزت حد {$_bk_limit['limit']} حجوزات/يوم لخطتك",
        'used'    => $_bk_limit['used'],
        'limit'   => $_bk_limit['limit'],
    ], 429);
}
unset($_bk_plan, $_bk_limit);
// END BRIDGE

if (!$provider_id || !$date || !$time)
    Kernel::respond(['error'=>'missing_fields','message'=>'حقول مطلوبة: provider_id, booking_date, booking_time'],400);

// Validate date (must be tomorrow or later)
if (strtotime($date) < strtotime('+1 day midnight'))
    Kernel::respond(['error'=>'invalid_date','message'=>'يجب أن يكون الحجز من الغد على الأقل'],400);

// Validate provider
$prov = db()->prepare('SELECT id, name FROM users WHERE id=? AND provider_verified=1 LIMIT 1');
$prov->execute([$provider_id]);
$provider = $prov->fetch();
if (!$provider) Kernel::respond(['error'=>'provider_not_found','message'=>'المزود غير موجود أو غير موثّق'],404);

// Validate service (if provided)
$amount = 0;
if ($service_id) {
    $svc = db()->prepare('SELECT id, title, price_sdg FROM provider_services WHERE id=? AND provider_id=? AND is_active=1 LIMIT 1');
    $svc->execute([$service_id, $provider_id]);
    $service = $svc->fetch();
    if (!$service) Kernel::respond(['error'=>'service_not_found','message'=>'الخدمة غير متاحة'],404);
    $amount = (float)($service['price_sdg'] ?? 0);
}

// Check time conflict — with DB-level locking to prevent double booking
// FIX 8: Check both exact time AND duration overlap
$duration_min = $service ? (int)($service['duration_min'] ?? 60) : 60;

try {
    db()->beginTransaction();
    $conflict = db()->prepare(
        "SELECT id FROM bookings
         WHERE provider_id=? AND booking_date=? AND status NOT IN ('cancelled','rejected')
         AND (
           booking_time = ?
           OR (
             booking_time < ADDTIME(?, SEC_TO_TIME(? * 60))
             AND ADDTIME(booking_time, SEC_TO_TIME(? * 60)) > ?
           )
         )
         LIMIT 1 FOR UPDATE"
    );
    $conflict->execute([
        $provider_id, $date,
        $time,                      // exact match
        $time, $duration_min,       // new booking end
        $duration_min, $time        // existing booking end vs new start
    ]);
    if ($conflict->fetch()) {
        db()->rollBack();
        Kernel::respond(['error'=>'time_conflict','message'=>'هذا الموعد محجوز أو متداخل — اختر وقتاً آخر'],409);
    }
} catch (Throwable $e) {
    try { db()->rollBack(); } catch(Throwable $rb){}
    // Fallback: exact time check only
    $conflict = db()->prepare(
        "SELECT id FROM bookings WHERE provider_id=? AND booking_date=? AND booking_time=?
         AND status NOT IN ('cancelled','rejected') LIMIT 1"
    );
    $conflict->execute([$provider_id, $date, $time]);
    if ($conflict->fetch()) Kernel::respond(['error'=>'time_conflict','message'=>'هذا الموعد محجوز — اختر وقتاً آخر'],409);
}

// INSERT booking
$_commission = (float)PricingEngine::getSetting('service_platform_fee', 10.0);
db()->prepare(
    'INSERT INTO bookings (user_id, provider_id, service_id, booking_date, booking_time,
     amount_sdg, commission_rate, consultation_type, meeting_link, status, notes)
     VALUES (?,?,?,?,?,?,?,?,?,"pending",?)'
)->execute([$u['id'], $provider_id, $service_id, $date, $time, $amount, $_commission, $consultation_type, $meeting_link, $notes]);
unset($_commission);

$bookingId = (int)db()->lastInsertId();
db()->commit(); // Release the FOR UPDATE lock

// FCM + notifications
$provToken = get_user_token($provider_id);
if ($provToken) send_push($provToken, 'حجز جديد! 📅', "طلب حجز من {$u['name']} — {$date} الساعة {$time}", ['tag'=>'booking','booking_id'=>(string)$bookingId]);
save_notification($provider_id, 'new_booking', 'حجز جديد', "من {$u['name']} — {$date} الساعة {$time}", ['booking_id'=>(string)$bookingId]);
save_notification($u['id'], 'booking_sent', 'تم إرسال طلبك ✅', "انتظر تأكيد {$provider['name']}", ['booking_id'=>(string)$bookingId]);

Logger::info('booking_created', [
    'booking_id'        => $bookingId,
    'provider_id'       => $provider_id,
    'consultation_type' => $consultation_type,
    'amount_sdg'        => $amount,
]);
Kernel::respond([
    'success'           => true,
    'booking_id'        => $bookingId,
    'status'            => 'pending',
    'consultation_type' => $consultation_type,
    'meeting_link'      => $meeting_link,
    'message'           => "تم إرسال طلب الحجز لـ {$provider['name']}. ستُخطَر عند التأكيد.",
    'next_steps'        => [
        'انتظر إشعار التأكيد',
        $consultation_type === 'video' ? 'رابط الفيديو سيصلك عند التأكيد' : 'حضر إلى العيادة في الموعد',
        'يمكنك إلغاء الطلب قبل التأكيد',
    ],
    'trace_id' => Logger::traceId(),
]);
