<?php
session_start();
ob_start();

// ─── Error Reporting (disable display_errors in production) ───────────────────
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', __DIR__ . '/../logs/booking_error.log');
error_reporting(E_ALL);

header('Content-Type: application/json; charset=utf-8');
header('X-Content-Type-Options: nosniff');

// ─── Valid ENUM Values (must match DB schema exactly) ─────────────────────────
const VALID_TYPES   = ['CONSULTATION', 'HEARING_TEST', 'FOLLOW_UP', 'PROCEDURE', 'EMERGENCY', 'TELEMEDICINE'];
const VALID_SOURCES = ['ONLINE', 'PHONE', 'WALK_IN', 'STAFF'];

// Types that do NOT require a chief complaint
const COMPLAINT_OPTIONAL = ['HEARING_TEST', 'PROCEDURE', 'TELEMEDICINE'];

$response      = ['success' => false, 'message' => 'Unknown error'];
$inTransaction = false;
$conn          = null;

try {
    error_log("Booking request received: " . json_encode($_POST));

    // ── DB Connection ──────────────────────────────────────────────────────────
    $dbconn_path = __DIR__ . '/../layouts/dbconn.php';
    if (!file_exists($dbconn_path)) {
        throw new Exception("DB config file not found.");
    }
    include $dbconn_path;

    if (!isset($conn) || !$conn || $conn->connect_error) {
        throw new Exception("DB connection failed: " . ($conn->connect_error ?? 'Unknown'));
    }

    // ── Auth ───────────────────────────────────────────────────────────────────
    if (!isset($_SESSION['user_id'])) {
        throw new Exception("Unauthorized access. Please log in.");
    }
    $created_by = (int) $_SESSION['user_id'];

    // ── Collect & Sanitise Input ───────────────────────────────────────────────
    $patient_id           = isset($_POST['patient_id'])           ? (int)   $_POST['patient_id']                    : 0;
    $guest_patient_name   = isset($_POST['guest_patient_name'])   ? trim(   $_POST['guest_patient_name'])            : '';
    $guest_patient_phone  = isset($_POST['guest_patient_phone'])  ? trim(   $_POST['guest_patient_phone'])           : '';
    $doctor_id            = isset($_POST['doctor_id'])            ? (int)   $_POST['doctor_id']                     : 0;
    $slot_id              = isset($_POST['slot_id'])              ? (int)   $_POST['slot_id']                       : 0;
    $appointment_date     = isset($_POST['appointment_date'])     ? trim(   $_POST['appointment_date'])              : '';
    $appointment_time     = isset($_POST['appointment_time'])     ? trim(   $_POST['appointment_time'])              : '';
    $appointment_type     = isset($_POST['appointment_type'])     ? strtoupper(trim($_POST['appointment_type']))     : '';
    $booking_source       = isset($_POST['booking_source'])       ? strtoupper(trim($_POST['booking_source']))       : 'STAFF';
    $chief_complaint      = isset($_POST['chief_complaint'])      ? trim(   $_POST['chief_complaint'])               : '';
    $special_requirements = isset($_POST['special_requirements']) ? trim(   $_POST['special_requirements'])          : '';
    $notes                = isset($_POST['notes'])                ? trim(   $_POST['notes'])                         : '';
    $room_number          = isset($_POST['room_number'])          ? trim(   $_POST['room_number'])                   : '';
    $estimated_duration   = isset($_POST['estimated_duration'])   ? (int)   $_POST['estimated_duration']            : 30;

    // ── Validate Required Fields ───────────────────────────────────────────────
    if (!$doctor_id) {
        throw new Exception("Please select a doctor.");
    }
    if (!$appointment_date) {
        throw new Exception("Please select an appointment date.");
    }
    if (!$appointment_time) {
        throw new Exception("Please select an appointment time.");
    }
    if (!$appointment_type) {
        throw new Exception("Please select an appointment type.");
    }

    // Patient: either existing patient_id OR guest details
    if ($patient_id <= 0) {
        if (empty($guest_patient_name) || empty($guest_patient_phone)) {
            throw new Exception("Please select a patient or enter guest name and phone number.");
        }
        if (strlen($guest_patient_name) < 2) {
            throw new Exception("Guest patient name must be at least 2 characters.");
        }
        if (strlen(preg_replace('/[^0-9]/', '', $guest_patient_phone)) < 8) {
            throw new Exception("Please enter a valid phone number (at least 8 digits).");
        }
    }

    // Chief complaint: only required for types where it makes clinical sense
    if (!in_array($appointment_type, COMPLAINT_OPTIONAL) && empty($chief_complaint)) {
        throw new Exception("Chief complaint is required for this appointment type.");
    }

    // ── Validate ENUM Values ───────────────────────────────────────────────────
    if (!in_array($appointment_type, VALID_TYPES)) {
        throw new Exception("Invalid appointment type: $appointment_type");
    }
    if (!in_array($booking_source, VALID_SOURCES)) {
        throw new Exception("Invalid booking source: $booking_source");
    }

    // ── Validate Date & Time Formats ───────────────────────────────────────────
    if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $appointment_date) || !DateTime::createFromFormat('Y-m-d', $appointment_date)) {
        throw new Exception("Invalid date format. Use YYYY-MM-DD.");
    }
    if (!preg_match('/^\d{2}:\d{2}(:\d{2})?$/', $appointment_time)) {
        throw new Exception("Invalid time format. Use HH:MM.");
    }

    // ── Normalise Nullable Fields ──────────────────────────────────────────────
    $slot_id              = $slot_id > 0          ? $slot_id              : null;
    $chief_complaint      = $chief_complaint      !== '' ? $chief_complaint      : null;
    $special_requirements = $special_requirements !== '' ? $special_requirements : null;
    $notes                = $notes                !== '' ? $notes                : null;
    $room_number          = $room_number          !== '' ? $room_number          : null;
    $estimated_duration   = $estimated_duration   >  0  ? $estimated_duration   : 30;

    // ── Begin Transaction ──────────────────────────────────────────────────────
    if (!$conn->begin_transaction()) {
        throw new Exception("Failed to start transaction: " . $conn->error);
    }
    $inTransaction = true;

    // ── Step 0: Create Guest Patient Record (if no patient_id) ────────────────
    if ($patient_id <= 0) {
        // Get PATIENT role ID
        $role_res = $conn->query("SELECT role_id FROM user_roles WHERE role_code = 'PATIENT' LIMIT 1");
        if (!$role_res || $role_res->num_rows === 0) {
            throw new Exception("Patient role not found in database.");
        }
        $patient_role_id = (int) $role_res->fetch_assoc()['role_id'];

        // Generate patient number
        $pn_res = $conn->query("SELECT GeneratePatientNumber() AS patient_number");
        if (!$pn_res) {
            throw new Exception("Failed to generate patient number.");
        }
        $patient_number = $pn_res->fetch_assoc()['patient_number'];
        $guest_email    = strtolower(preg_replace('/[^a-z0-9]/', '', $patient_number)) . '@prodigykenya.com';

        // Insert user
        $ustmt = $conn->prepare(
            "INSERT INTO users (user_type, email, full_name, phone_primary, role_id, status,
             date_of_birth, gender, created_at)
             VALUES ('PATIENT', ?, ?, ?, ?, 'ACTIVE', '2000-01-01', 'OTHER', NOW())"
        );
        if (!$ustmt) {
            throw new Exception("Failed to prepare guest user insert: " . $conn->error);
        }
        $ustmt->bind_param("sssi", $guest_email, $guest_patient_name, $guest_patient_phone, $patient_role_id);
        if (!$ustmt->execute()) {
            throw new Exception("Failed to create guest user: " . $ustmt->error);
        }
        $new_user_id = $conn->insert_id;
        $ustmt->close();

        // Insert patient
        $pstmt = $conn->prepare(
            "INSERT INTO patients (user_id, patient_number, registration_type, is_active, created_at)
             VALUES (?, ?, 'WALK_IN', 1, NOW())"
        );
        if (!$pstmt) {
            throw new Exception("Failed to prepare guest patient insert: " . $conn->error);
        }
        $pstmt->bind_param("is", $new_user_id, $patient_number);
        if (!$pstmt->execute()) {
            throw new Exception("Failed to create guest patient: " . $pstmt->error);
        }
        $patient_id = $conn->insert_id;
        $pstmt->close();
    }

    // ── Step 1: Check Slot / Double-Booking ───────────────────────────────────
    if ($slot_id !== null) {
        // Verify pre-defined slot is still available
        $slot_stmt = $conn->prepare(
            "SELECT slot_id, booked_patients, max_patients
             FROM appointment_slots
             WHERE slot_id = ? AND doctor_id = ?
             AND slot_date = ? AND start_time = ? AND is_available = 1
             LIMIT 1"
        );
        if (!$slot_stmt) {
            throw new Exception("Failed to prepare slot check: " . $conn->error);
        }
        $slot_stmt->bind_param("iiss", $slot_id, $doctor_id, $appointment_date, $appointment_time);
        $slot_stmt->execute();
        $slot = $slot_stmt->get_result()->fetch_assoc();
        $slot_stmt->close();

        if (!$slot) {
            throw new Exception("Selected slot is no longer available. Please choose another.");
        }
        if ($slot['booked_patients'] >= $slot['max_patients']) {
            throw new Exception("This slot is already fully booked.");
        }
    } else {
        // No pre-defined slot: prevent double-booking the same doctor/date/time
        $dup_stmt = $conn->prepare(
            "SELECT 1 FROM appointments
             WHERE doctor_id = ? AND appointment_date = ? AND appointment_time = ?
             AND status NOT IN ('CANCELLED', 'NO_SHOW')
             LIMIT 1"
        );
        if (!$dup_stmt) {
            throw new Exception("Failed to prepare duplicate check: " . $conn->error);
        }
        $dup_stmt->bind_param("iss", $doctor_id, $appointment_date, $appointment_time);
        $dup_stmt->execute();
        if ($dup_stmt->get_result()->num_rows > 0) {
            throw new Exception("This date and time is already booked for this doctor. Please choose another slot.");
        }
        $dup_stmt->close();
    }

    // ── Step 2: Generate Appointment Number ───────────────────────────────────
    $today    = date('Ymd');
    $num_stmt = $conn->prepare(
        "SELECT appointment_number FROM appointments
         WHERE appointment_number LIKE ?
         ORDER BY appointment_id DESC LIMIT 1"
    );
    if (!$num_stmt) {
        throw new Exception("Failed to prepare appointment number query: " . $conn->error);
    }
    $like_pattern = "APP-$today-%";
    $num_stmt->bind_param("s", $like_pattern);
    $num_stmt->execute();
    $num_result = $num_stmt->get_result()->fetch_assoc();
    $num_stmt->close();

    $new_sequence       = $num_result
        ? str_pad((int) substr($num_result['appointment_number'], -4) + 1, 4, '0', STR_PAD_LEFT)
        : '0001';
    $appointment_number = "APP-$today-$new_sequence";

    // ── Step 3: Insert Appointment ────────────────────────────────────────────
    $insert_stmt = $conn->prepare(
        "INSERT INTO appointments (
            appointment_number, patient_id, doctor_id, slot_id,
            appointment_date, appointment_time, appointment_type, booking_source,
            chief_complaint, special_requirements, estimated_duration,
            room_number, notes, status, created_at
        ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'SCHEDULED', NOW())"
    );
    if (!$insert_stmt) {
        throw new Exception("Failed to prepare appointment insert: " . $conn->error);
    }
    $insert_stmt->bind_param(
        "siiissssssiss",
        $appointment_number,
        $patient_id,
        $doctor_id,
        $slot_id,
        $appointment_date,
        $appointment_time,
        $appointment_type,
        $booking_source,
        $chief_complaint,
        $special_requirements,
        $estimated_duration,
        $room_number,
        $notes
    );
    if (!$insert_stmt->execute()) {
        throw new Exception("Failed to insert appointment: " . $insert_stmt->error);
    }
    $appointment_id = $conn->insert_id;
    $insert_stmt->close();

    // ── Step 4: Update Slot Availability ──────────────────────────────────────
    if ($slot_id !== null) {
        $slot_upd = $conn->prepare(
            "UPDATE appointment_slots
             SET booked_patients = booked_patients + 1,
                 is_available = CASE WHEN booked_patients + 1 >= max_patients THEN 0 ELSE 1 END
             WHERE slot_id = ?"
        );
        if (!$slot_upd) {
            throw new Exception("Failed to prepare slot update: " . $conn->error);
        }
        $slot_upd->bind_param("i", $slot_id);
        if (!$slot_upd->execute()) {
            throw new Exception("Failed to update slot availability: " . $slot_upd->error);
        }
        $slot_upd->close();
    }

    // ── Commit ─────────────────────────────────────────────────────────────────
    if (!$conn->commit()) {
        throw new Exception("Commit failed: " . $conn->error);
    }
    $inTransaction = false;

    $response = [
        'success'            => true,
        'message'            => "Appointment booked successfully! Reference: $appointment_number",
        'appointment_id'     => $appointment_id,
        'appointment_number' => $appointment_number
    ];

    // ── WhatsApp Notification (non-fatal) ─────────────────────────────────────
    try {
        $doc_stmt = $conn->prepare(
            "SELECT u.full_name, u.phone_primary
             FROM doctors d JOIN users u ON d.user_id = u.user_id
             WHERE d.doctor_id = ? LIMIT 1"
        );
        $doc_stmt->bind_param("i", $doctor_id);
        $doc_stmt->execute();
        $doc = $doc_stmt->get_result()->fetch_assoc();
        $doc_stmt->close();

        $pat_stmt = $conn->prepare(
            "SELECT u.full_name
             FROM patients p JOIN users u ON p.user_id = u.user_id
             WHERE p.patient_id = ? LIMIT 1"
        );
        $pat_stmt->bind_param("i", $patient_id);
        $pat_stmt->execute();
        $pat = $pat_stmt->get_result()->fetch_assoc();
        $pat_stmt->close();

        if ($doc && $pat) {
            $wa_path = __DIR__ . '/../includes/WhatsAppIntegration.php';
            if (file_exists($wa_path)) {
                require_once $wa_path;
                $wa = new WhatsAppIntegration($conn);
                $wa->sendAppointmentNotification(
                    $doc['phone_primary'],
                    $doc['full_name'],
                    $pat['full_name'],
                    $appointment_date,
                    $appointment_time
                );
            }
        }
    } catch (Exception $e) {
        error_log("WhatsApp notification failed (non-fatal): " . $e->getMessage());
    }

} catch (Exception $e) {
    if ($inTransaction && $conn) {
        $conn->rollback();
        $inTransaction = false;
    }
    $response = [
        'success' => false,
        'message' => $e->getMessage()
    ];
    error_log("Booking error: " . $e->getMessage() . " | POST: " . json_encode($_POST ?? []));

} finally {
    if ($conn) {
        $conn->close();
    }
}

ob_end_clean();
echo json_encode($response, JSON_UNESCAPED_SLASHES);
exit;
?>