<?php
/**
 * Kitchen Update Order Status API
 * Allows kitchen staff to update order/item status (preparing, ready, etc.)
 */

session_start();
header('Content-Type: application/json');
require_once 'config.php';
require_once 'ingredient_unit_helper.php';

function ensureOrderNotificationTable($conn) {
    $create_table_sql = "CREATE TABLE IF NOT EXISTS order_notifications (
        id INT PRIMARY KEY AUTO_INCREMENT,
        order_id INT NOT NULL,
        server_id INT NOT NULL,
        item_id INT NULL,
        notification_type VARCHAR(50) DEFAULT 'item_ready',
        message TEXT,
        is_read INT DEFAULT 0,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        FOREIGN KEY (order_id) REFERENCES dine_in_orders(id) ON DELETE CASCADE,
        FOREIGN KEY (server_id) REFERENCES servers(id) ON DELETE CASCADE
    )";
    $conn->query($create_table_sql);

    $item_id_col = $conn->query("SHOW COLUMNS FROM order_notifications LIKE 'item_id'");
    if (!$item_id_col || $item_id_col->num_rows === 0) {
        if (!$conn->query("ALTER TABLE order_notifications ADD COLUMN item_id INT NULL AFTER server_id")) {
            throw new Exception('Failed to add item_id to order_notifications: ' . $conn->error);
        }
    }
}

function hasUnreadOrderNotification($conn, $order_id, $server_id, $notification_type, $item_id = null) {
    $sql = "SELECT id
            FROM order_notifications
            WHERE order_id = ?
              AND server_id = ?
              AND notification_type = ?
              AND is_read = 0";

    if ($item_id !== null) {
        $sql .= " AND item_id = ?";
        $stmt = $conn->prepare($sql);
        if (!$stmt) {
            throw new Exception('Failed to prepare notification lookup: ' . $conn->error);
        }
        $stmt->bind_param('iisi', $order_id, $server_id, $notification_type, $item_id);
    } else {
        $stmt = $conn->prepare($sql);
        if (!$stmt) {
            throw new Exception('Failed to prepare notification lookup: ' . $conn->error);
        }
        $stmt->bind_param('iis', $order_id, $server_id, $notification_type);
    }

    $stmt->execute();
    $result = $stmt->get_result();
    $exists = $result && $result->num_rows > 0;
    $stmt->close();

    return $exists;
}

function ensureIngredientAllocationsTable($conn) {
    $create_table_sql = "CREATE TABLE IF NOT EXISTS ingredient_allocations (
        id INT PRIMARY KEY AUTO_INCREMENT,
        order_id INT NOT NULL,
        item_id INT NOT NULL,
        ingredient_id INT NOT NULL,
        quantity_allocated DECIMAL(10, 3) NOT NULL,
        unit VARCHAR(50) NOT NULL,
        status VARCHAR(50) DEFAULT 'allocated',
        allocated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        used_at TIMESTAMP NULL,
        notes TEXT,
        FOREIGN KEY (order_id) REFERENCES dine_in_orders(id) ON DELETE CASCADE,
        FOREIGN KEY (item_id) REFERENCES dine_in_order_items(id) ON DELETE CASCADE,
        FOREIGN KEY (ingredient_id) REFERENCES ingredients(id) ON DELETE CASCADE,
        INDEX idx_order (order_id),
        INDEX idx_item (item_id),
        INDEX idx_status (status)
    )";

    if (!$conn->query($create_table_sql)) {
        throw new Exception('Failed to ensure ingredient_allocations table: ' . $conn->error);
    }
}

function allocateIngredientsForOrderItem($conn, $order_id, $order_item_id) {
    ensureIngredientAllocationsTable($conn);

    $existing_stmt = $conn->prepare("
        SELECT COUNT(*) AS allocation_count
        FROM ingredient_allocations
        WHERE order_id = ? AND item_id = ?
    ");
    if (!$existing_stmt) {
        throw new Exception('Failed to prepare allocation lookup: ' . $conn->error);
    }
    $existing_stmt->bind_param('ii', $order_id, $order_item_id);
    $existing_stmt->execute();
    $existing_result = $existing_stmt->get_result();
    $existing_row = $existing_result->fetch_assoc();
    $existing_stmt->close();

    if (!empty($existing_row['allocation_count'])) {
        return [
            'allocated' => false,
            'skipped' => true,
            'reason' => 'already_allocated'
        ];
    }

    $item_stmt = $conn->prepare("
        SELECT id, item_id, item_name, quantity
        FROM dine_in_order_items
        WHERE id = ? AND dine_in_order_id = ?
        LIMIT 1
    ");
    if (!$item_stmt) {
        throw new Exception('Failed to prepare order item lookup: ' . $conn->error);
    }
    $item_stmt->bind_param('ii', $order_item_id, $order_id);
    $item_stmt->execute();
    $item_result = $item_stmt->get_result();
    $order_item = $item_result->fetch_assoc();
    $item_stmt->close();

    if (!$order_item) {
        throw new Exception('Order item not found for ingredient allocation');
    }

    $recipe_stmt = $conn->prepare("
        SELECT id
        FROM recipes
        WHERE menu_item_id = ? AND status IN ('active', 'draft')
        LIMIT 1
    ");
    if (!$recipe_stmt) {
        throw new Exception('Failed to prepare recipe lookup: ' . $conn->error);
    }
    $recipe_stmt->bind_param('i', $order_item['item_id']);
    $recipe_stmt->execute();
    $recipe_result = $recipe_stmt->get_result();
    $recipe = $recipe_result->fetch_assoc();
    $recipe_stmt->close();

    if (!$recipe) {
        return [
            'allocated' => false,
            'skipped' => true,
            'reason' => 'no_recipe'
        ];
    }

    $ingredients_stmt = $conn->prepare("
        SELECT
            ri.ingredient_id,
            ri.quantity_required,
            ri.unit,
            i.name AS ingredient_name,
            i.current_stock,
            i.unit AS ingredient_unit
        FROM recipe_ingredients ri
        INNER JOIN ingredients i ON i.id = ri.ingredient_id
        WHERE ri.recipe_id = ?
        FOR UPDATE
    ");
    if (!$ingredients_stmt) {
        throw new Exception('Failed to prepare recipe ingredients lookup: ' . $conn->error);
    }
    $ingredients_stmt->bind_param('i', $recipe['id']);
    $ingredients_stmt->execute();
    $ingredients_result = $ingredients_stmt->get_result();

    $ingredients = [];
    $shortages = [];
    $item_quantity = (float)$order_item['quantity'];

    while ($row = $ingredients_result->fetch_assoc()) {
        $required_quantity = (float)$row['quantity_required'] * $item_quantity;
        $required_in_stock_unit = convertMeasurementQuantity($required_quantity, $row['unit'], $row['ingredient_unit']);
        if ($required_in_stock_unit === null) {
            $required_in_stock_unit = $required_quantity;
        }
        $current_stock = (float)$row['current_stock'];

        $ingredients[] = [
            'ingredient_id' => (int)$row['ingredient_id'],
            'ingredient_name' => $row['ingredient_name'],
            'required_quantity' => $required_in_stock_unit,
            'unit' => $row['ingredient_unit'],
            'current_stock' => $current_stock
        ];

        if ($current_stock < $required_in_stock_unit) {
            $shortages[] = $row['ingredient_name'] . ' (need ' . rtrim(rtrim(number_format($required_quantity, 3, '.', ''), '0'), '.') . ' ' . $row['unit'] . ', have ' . rtrim(rtrim(number_format($current_stock, 3, '.', ''), '0'), '.') . ' ' . $row['ingredient_unit'] . ')';
        }
    }
    $ingredients_stmt->close();

    if (empty($ingredients)) {
        return [
            'allocated' => false,
            'skipped' => true,
            'reason' => 'no_recipe_ingredients'
        ];
    }

    if (!empty($shortages)) {
        throw new Exception('Insufficient stock for "' . $order_item['item_name'] . '": ' . implode(', ', $shortages));
    }

    $update_stmt = $conn->prepare("UPDATE ingredients SET current_stock = current_stock - ? WHERE id = ?");
    $insert_stmt = $conn->prepare("
        INSERT INTO ingredient_allocations (
            order_id, item_id, ingredient_id, quantity_allocated, unit, status, used_at, notes
        ) VALUES (?, ?, ?, ?, ?, 'used', NOW(), ?)
    ");

    if (!$update_stmt || !$insert_stmt) {
        throw new Exception('Failed to prepare stock allocation statements: ' . $conn->error);
    }

    foreach ($ingredients as $ingredient) {
        $allocation_note = 'Auto-deducted when kitchen started preparation';

        $update_stmt->bind_param('di', $ingredient['required_quantity'], $ingredient['ingredient_id']);
        if (!$update_stmt->execute()) {
            throw new Exception('Failed to deduct ingredient stock: ' . $update_stmt->error);
        }

        $insert_stmt->bind_param(
            'iiidss',
            $order_id,
            $order_item_id,
            $ingredient['ingredient_id'],
            $ingredient['required_quantity'],
            $ingredient['unit'],
            $allocation_note
        );
        if (!$insert_stmt->execute()) {
            throw new Exception('Failed to record ingredient allocation: ' . $insert_stmt->error);
        }
    }

    $update_stmt->close();
    $insert_stmt->close();

    return [
        'allocated' => true,
        'skipped' => false,
        'reason' => null
    ];
}

function allocateIngredientsForOrder($conn, $order_id) {
    $items_stmt = $conn->prepare("
        SELECT id
        FROM dine_in_order_items
        WHERE dine_in_order_id = ?
          AND status IN ('pending', 'preparing')
        ORDER BY created_at ASC, id ASC
    ");
    if (!$items_stmt) {
        throw new Exception('Failed to prepare order items lookup: ' . $conn->error);
    }
    $items_stmt->bind_param('i', $order_id);
    $items_stmt->execute();
    $items_result = $items_stmt->get_result();

    while ($item = $items_result->fetch_assoc()) {
        allocateIngredientsForOrderItem($conn, $order_id, (int)$item['id']);
    }

    $items_stmt->close();
}

$input = json_decode(file_get_contents('php://input'), true);

if (!$input || !isset($input['order_id'])) {
    echo json_encode(['success' => false, 'message' => 'Invalid request. Missing order_id.']);
    exit;
}

$order_id = (int)$input['order_id'];
$action = isset($input['action']) ? $input['action'] : null;
$item_id = isset($input['item_id']) ? (int)$input['item_id'] : null;
$new_status = isset($input['status']) ? $input['status'] : null;

if (!$action) {
    echo json_encode(['success' => false, 'message' => 'Action not specified']);
    exit;
}

try {
    $transactionStarted = false;
    $valid_statuses = ['pending', 'preparing', 'ready'];
    
    if ($action === 'start_preparation') {
        $conn->begin_transaction();
        $transactionStarted = true;

        // Start preparing the order - update order status to 'preparing'
        $verify_sql = "SELECT id, status FROM dine_in_orders WHERE id = $order_id";
        $verify_result = $conn->query($verify_sql);
        
        if (!$verify_result || $verify_result->num_rows === 0) {
            $conn->rollback();
            echo json_encode(['success' => false, 'message' => 'Order not found']);
            exit;
        }

        allocateIngredientsForOrder($conn, $order_id);
        
        // Update order status to preparing
        $update_order_sql = "UPDATE dine_in_orders SET status = 'preparing' WHERE id = $order_id";
        
        if (!$conn->query($update_order_sql)) {
            throw new Exception('Failed to update order status: ' . $conn->error);
        }

        // Sync latest KOT status/timestamps for this order
        $kot_update_sql = "
            UPDATE kot_tickets
            SET
                status = 'preparing',
                acknowledged_at = COALESCE(acknowledged_at, NOW()),
                started_at = COALESCE(started_at, NOW())
            WHERE order_id = $order_id
            ORDER BY id DESC
            LIMIT 1
        ";
        $conn->query($kot_update_sql);

        $conn->commit();
        $transactionStarted = false;
        
        echo json_encode([
            'success' => true,
            'message' => 'Order preparation started',
            'order_id' => $order_id,
            'status' => 'preparing'
        ]);
        
    } elseif ($action === 'update_item_status') {
        $conn->begin_transaction();
        $transactionStarted = true;

        // Update individual item status
        if (!$item_id || !$new_status) {
            $conn->rollback();
            echo json_encode(['success' => false, 'message' => 'Missing item_id or status']);
            exit;
        }
        
        if (!in_array($new_status, $valid_statuses)) {
            $conn->rollback();
            echo json_encode(['success' => false, 'message' => 'Invalid status value']);
            exit;
        }
        
        // Verify item belongs to this order
        $verify_sql = "SELECT id, item_name, quantity FROM dine_in_order_items WHERE id = $item_id AND dine_in_order_id = $order_id";
        $verify_result = $conn->query($verify_sql);
        
        if (!$verify_result || $verify_result->num_rows === 0) {
            $conn->rollback();
            echo json_encode(['success' => false, 'message' => 'Item not found in this order']);
            exit;
        }
        
        $item_data = $verify_result->fetch_assoc();

        if ($new_status === 'preparing') {
            allocateIngredientsForOrderItem($conn, $order_id, $item_id);
        }
        
        // Update item status
        $update_sql = "UPDATE dine_in_order_items SET status = '$new_status' WHERE id = $item_id";
        
        if (!$conn->query($update_sql)) {
            throw new Exception('Failed to update item status: ' . $conn->error);
        }
        
        // Check whether any kitchen-active items still need work.
        // Served/cancelled rows are from completed flow and must not block or re-open readiness.
        $check_ready_sql = "SELECT COUNT(*) as pending_count
                            FROM dine_in_order_items
                            WHERE dine_in_order_id = $order_id
                              AND status NOT IN ('ready', 'served', 'cancelled')";
        $check_result = $conn->query($check_ready_sql);
        $check_data = $check_result->fetch_assoc();
        
        $order_status = $check_data['pending_count'] > 0 ? 'preparing' : 'ready';
        
        // Update order status accordingly
        $update_order_sql = "UPDATE dine_in_orders SET status = '$order_status' WHERE id = $order_id";
        $conn->query($update_order_sql);

        // Sync latest KOT status/timestamps based on aggregate item progress
        if ($order_status === 'ready') {
            $kot_update_sql = "
                UPDATE kot_tickets
                SET
                    status = 'completed',
                    acknowledged_at = COALESCE(acknowledged_at, NOW()),
                    started_at = COALESCE(started_at, NOW()),
                    completed_at = COALESCE(completed_at, NOW())
                WHERE order_id = $order_id
                ORDER BY id DESC
                LIMIT 1
            ";
            $conn->query($kot_update_sql);
        } else {
            $kot_update_sql = "
                UPDATE kot_tickets
                SET
                    status = 'preparing',
                    acknowledged_at = COALESCE(acknowledged_at, NOW()),
                    started_at = COALESCE(started_at, NOW())
                WHERE order_id = $order_id
                ORDER BY id DESC
                LIMIT 1
            ";
            $conn->query($kot_update_sql);
        }
        
        // Send notification to server when item becomes ready.
        // If this update makes the whole order ready, create a single order-level
        // notification instead of stacking both item_ready and ready notifications.
        if ($new_status === 'ready') {
            $order_sql = "SELECT server_id FROM dine_in_orders WHERE id = $order_id";
            $order_result = $conn->query($order_sql);
            if ($order_result && $order_result->num_rows > 0) {
                $order_data = $order_result->fetch_assoc();
                $server_id = (int)$order_data['server_id'];
                
                ensureOrderNotificationTable($conn);

                if ($server_id > 0) {
                    if ($order_status === 'ready') {
                        if (!hasUnreadOrderNotification($conn, $order_id, $server_id, 'ready')) {
                            $message = "Your order is ready for pickup!";
                            $notification_stmt = $conn->prepare("
                                INSERT INTO order_notifications (order_id, server_id, notification_type, message, is_read)
                                VALUES (?, ?, 'ready', ?, 0)
                            ");
                            if (!$notification_stmt) {
                                throw new Exception('Failed to prepare ready notification: ' . $conn->error);
                            }
                            $notification_stmt->bind_param('iis', $order_id, $server_id, $message);
                            if (!$notification_stmt->execute()) {
                                throw new Exception('Failed to create ready notification: ' . $notification_stmt->error);
                            }
                            $notification_stmt->close();
                        }
                    } else {
                        if (!hasUnreadOrderNotification($conn, $order_id, $server_id, 'item_ready', $item_id)) {
                            $item_name_safe = addslashes($item_data['item_name']);
                            $message = "Item \"{$item_name_safe}\" is ready for serving!";
                            $notification_sql = "INSERT INTO order_notifications (order_id, server_id, item_id, notification_type, message, is_read) 
                                                 VALUES ($order_id, $server_id, $item_id, 'item_ready', '$message', 0)";
                            if (!$conn->query($notification_sql)) {
                                throw new Exception('Failed to create item-ready notification: ' . $conn->error);
                            }
                        }
                    }
                }
            }
        }

        $conn->commit();
        $transactionStarted = false;
        
        echo json_encode([
            'success' => true,
            'message' => 'Item status updated successfully',
            'item_id' => $item_id,
            'item_name' => $item_data['item_name'],
            'item_status' => $new_status,
            'order_status' => $order_status
        ]);
        
    } elseif ($action === 'mark_order_ready') {
        $conn->begin_transaction();
        $transactionStarted = true;

        // Mark entire order as ready
        // First verify order exists
        $verify_sql = "SELECT id, status FROM dine_in_orders WHERE id = $order_id";
        $verify_result = $conn->query($verify_sql);
        
        if (!$verify_result || $verify_result->num_rows === 0) {
            $conn->rollback();
            echo json_encode(['success' => false, 'message' => 'Order not found']);
            exit;
        }
        
        $order_data = $verify_result->fetch_assoc();

        if ($order_data['status'] === 'confirmed') {
            $conn->rollback();
            echo json_encode([
                'success' => false,
                'message' => 'Start the order before marking it done'
            ]);
            exit;
        }
        
        // Update only kitchen-active items to ready.
        // Never rewrite already served rows back to ready.
        $update_items_sql = "UPDATE dine_in_order_items
                             SET status = 'ready'
                             WHERE dine_in_order_id = $order_id
                               AND status IN ('pending', 'preparing')";
        $conn->query($update_items_sql);
        
        // Update order status to ready
        $update_order_sql = "UPDATE dine_in_orders SET status = 'ready' WHERE id = $order_id";
        
        if (!$conn->query($update_order_sql)) {
            throw new Exception('Failed to update order status: ' . $conn->error);
        }

        // Sync latest KOT as completed
        $kot_update_sql = "
            UPDATE kot_tickets
            SET
                status = 'completed',
                acknowledged_at = COALESCE(acknowledged_at, NOW()),
                started_at = COALESCE(started_at, NOW()),
                completed_at = COALESCE(completed_at, NOW())
            WHERE order_id = $order_id
            ORDER BY id DESC
            LIMIT 1
        ";
        $conn->query($kot_update_sql);

        $order_sql = "SELECT server_id, order_number FROM dine_in_orders WHERE id = $order_id";
        $order_result = $conn->query($order_sql);
        if ($order_result && $order_result->num_rows > 0) {
            $server_data = $order_result->fetch_assoc();
            $server_id = (int)$server_data['server_id'];

            if ($server_id > 0) {
                ensureOrderNotificationTable($conn);

                if (!hasUnreadOrderNotification($conn, $order_id, $server_id, 'ready')) {
                    $order_number_safe = addslashes($server_data['order_number']);
                    $message = "Order {$order_number_safe} is ready for pickup!";
                    $notification_sql = "INSERT INTO order_notifications (order_id, server_id, notification_type, message, is_read)
                                         VALUES ($order_id, $server_id, 'ready', '$message', 0)";
                    if (!$conn->query($notification_sql)) {
                        throw new Exception('Failed to create ready notification: ' . $conn->error);
                    }
                }
            }
        }

        $conn->commit();
        $transactionStarted = false;
        
        echo json_encode([
            'success' => true,
            'message' => 'Order marked as ready for serving',
            'order_id' => $order_id,
            'status' => 'ready'
        ]);
        
    } else {
        echo json_encode(['success' => false, 'message' => 'Invalid action']);
    }
    
} catch (Exception $e) {
    if (!empty($transactionStarted)) {
        try {
            $conn->rollback();
        } catch (Throwable $rollbackError) {
            // Ignore rollback errors and return the original exception.
        }
    }
    http_response_code(500);
    echo json_encode([
        'success' => false,
        'message' => $e->getMessage()
    ]);
}
?>
