<?php
/**
 * ajax_for_assmbly.php  (office / Assembly-admin AJAX endpoints)
 * =====================================================================
 * CHANGES FROM ORIGINAL:
 *
 *   1. recalculateMachineDatesforassbly() removed — this file's copy was
 *      the one with the stale `end_date >= today` filter instead of
 *      `finished = 0` (see assbly_scheduler_lib.php header for the full
 *      writeup — this was the more consequential of the family-pattern
 *      bugs here, since it lived in the reschedule engine itself, not
 *      just a priority-renumbering query). Now uses
 *      assbly_fullReschedule().
 *
 *   2. select_order_for_assmbly's inline shift-walking loop (a 3rd copy
 *      of the same scheduling primitive) replaced with
 *      assbly_scheduleNewTaskInline().
 *
 *   3. update_assmbly_task_priority: FIX — both the old-machine
 *      renumbering query and the new-machine priority-shift query
 *      filtered `end_date >= today`, the same stale-row bug found in
 *      CNC's/PU's/VAC's/Assypu's equivalent endpoints. Now filters
 *      `finished = 0`.
 *
 *   4. add_assbly_break: FIX — `$priority` (meant to place the break
 *      ahead of the selected "highest priority" task) was computed and
 *      then never used; the insert always used `$new_priority`
 *      (MAX+1), silently appending to the back of the queue. The
 *      follow-up priority-shift had no condition beyond machine_id at
 *      all, bumping every row regardless of position. No reschedule
 *      call at all. All three fixed, same pattern as CNC/PU/VAC/Assypu.
 *
 *   5. start_machine_breakdown / stop_machine_breakdown now mirror into
 *      assbly_machine_breakdown_log, the table the dashboard's
 *      assbly_isMachineInBreakdown() check actually reads — previously
 *      a breakdown started here was invisible to the tablet. stop now
 *      also calls assbly_fullReschedule() (previously never did).
 *
 *   6. get_machine_breakdown_status now reads assbly_machine_breakdown_log,
 *      consistent with the shared source of truth.
 *
 *   7. get_assmbly_task_details: FIX — `$data['is_late']` was computed
 *      against `$row['manufacture_end_date']` / `$row['end_date']`, but
 *      `$row` was never set in this handler (it's a copy-paste leftover
 *      — the fetched row is `$data`, not `$row`). `empty($row[...])` on
 *      an undefined variable is always true, so `is_late` could never
 *      become `true`. Changed to reference `$data`. The same handler
 *      also reused `$query`/`$result`/`$row` for the customer-ref
 *      lookup right after — renamed those locals so they don't clobber
 *      the outer values before the is_late fix runs.
 *
 *   8. markBreakdownAffectedWorkOrders() and the split-work-order logic
 *      removed from this file — now the shared
 *      assbly_markBreakdownAffectedWorkOrders() / assbly_splitTask().
 * =====================================================================
 */
include("../../../include/startup.php");
require_once __DIR__ . '/assbly_scheduler_lib.php';

header('Content-Type: application/json');
error_reporting(E_ALL);
ini_set('display_errors', 1);

/* =====================================================================
 * select_order_for_assmbly
 * ===================================================================== */
if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'select_order_for_assmbly') {

    $json_data   = $_REQUEST['work_orders'];
    $work_orders = json_decode($json_data, true);

    $inserted           = false;
    $processed_machines = [];
    $shiftsByDay = assbly_getShiftsByDay($conn);

    foreach ($work_orders as $item) {
        $id            = (int) $item['id'];
        $work_order_id = (int) $item['work_order_id'];
        $part_id       = (int) $item['part_id'];
        $machine_id    = (int) $item['machine_id'];

        $processed_machines[$machine_id] = true;

        $selectQuery = "
            SELECT part_id, id, parent_ids, end_date, quantity, product_name, total_hours, set_id
            FROM manufacture_machine_table WHERE id = $id";
        $result = $conn->query($selectQuery);

        if ($result && $result->num_rows > 0) {
            $row = $result->fetch_assoc();

            $quantity      = (int) $row['quantity'];
            $manuf_id      = (int) $row['id'];
            $product_name  = $row['product_name'];
            $total_hoursss = $row['total_hours'];
            $set_id        = $row['set_id'];
            $setup_hours   = 0;

            if ($set_id > 0) {
                $query_route = "SELECT operation_time, parts_per_operation, set_time, machine_high_priority FROM set_route_details WHERE set_id = $set_id";
            } else {
                $query_route = "SELECT operation_time, parts_per_operation, set_time, machine_high_priority FROM route_details WHERE item_id = $part_id";
            }
            $result_route = $conn->query($query_route);

            if ($result_route && $result_route->num_rows > 0) {
                $row_route = $result_route->fetch_assoc();
                $set_time = $row_route['set_time'];
                [$hours, $minutes, $seconds] = explode(':', $set_time);
                $setup_hours = $hours + ($minutes / 60) + ($seconds / 3600);

                if (!empty($row_route['operation_time'])) {
                    [$h, $m, $s] = explode(":", $row_route['operation_time']);
                    $operation_time = ($h * 60) + $m + ($s / 60);
                } else {
                    $operation_time = 1;
                }
                $parts_per_operation = (!empty($row_route['parts_per_operation']) && $row_route['parts_per_operation'] > 0)
                    ? (float) $row_route['parts_per_operation'] : 1;
                $cycle = (int) round($operation_time / $parts_per_operation);
            } else {
                $cycle = 1;
            }
            $total_hours = $total_hoursss + $setup_hours;

            $query_priority = "SELECT MAX(priority) AS priority FROM assbly_machine_table WHERE machine_id = $machine_id";
            $result_priority = mysqli_query($conn, $query_priority);
            if ($result_priority && mysqli_num_rows($result_priority) > 0) {
                $rowp = mysqli_fetch_assoc($result_priority);
                $currentPriority = $rowp['priority'] ?? 0;
                $new_priority = $currentPriority + 1;
            } else {
                $new_priority = 1;
            }

            // FIX: was a 3rd inline copy of the shift-walking loop; now
            // the shared primitive every other scheduling path uses.
            $scheduleData = assbly_scheduleNewTaskInline($conn, $total_hours, $shiftsByDay);
            $startStr = $scheduleData['start_date'];
            $endStr   = $scheduleData['end_date'];
            $firstShiftUsed = mysqli_real_escape_string($conn, (string) $scheduleData['shift_ids']);
            $remainingHoursStr = mysqli_real_escape_string($conn, $scheduleData['remaining_hours']);

            $insertQuery = "
                INSERT INTO assbly_machine_table
                (machine_id, manuf_id, work_order_id, part_id, end_date, start_date, quantity, shift_ids, product_name, total_hours, total_hours_update, setup_hours, cycle, set_id, priority, remaing_hours)
                VALUES (
                    $machine_id, $manuf_id, $work_order_id, $part_id,
                    '$endStr', '$startStr', $quantity, '$firstShiftUsed', '$product_name',
                    '$total_hours', '$total_hoursss', '$setup_hours', '$cycle', '$set_id', '$new_priority', '$remainingHoursStr'
                )";

            if ($conn->query($insertQuery)) {
                $inserted = true;
                $conn->query("UPDATE manufacture_machine_table SET in_scheduler_check = 1 WHERE id = $id");
            }
        }
    }

    foreach (array_keys($processed_machines) as $machine_id) {
        assbly_fullReschedule($conn, $machine_id);
    }

    echo json_encode($inserted
        ? ['status' => 'success']
        : ['status' => 'failed', 'message' => 'No rows inserted']);
    exit;
}

/* =====================================================================
 * update_assmbly_task_priority — drag and drop
 * ===================================================================== */
else if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'update_assmbly_task_priority') {

    $taskId       = intval($_REQUEST['task_id']);
    $newMachineId = intval($_REQUEST['new_machine_id']);
    $leftNeighborPriority = isset($_REQUEST['left_neighbor_priority']) ? intval($_REQUEST['left_neighbor_priority']) : null;

    $draggedTask = $conn->query("SELECT * FROM assbly_machine_table WHERE id = $taskId")->fetch_assoc();
    if (!$draggedTask) {
        echo json_encode(['status' => 'error', 'message' => 'Task not found']);
        exit;
    }

    // FIX: filters `finished = 0`, not `end_date >= today` -- a stale
    // end_date previously kept a row at its old priority number while
    // everything else got renumbered around it.
    $originalTasks = [];
    $originalResult = mysqli_query($conn, "
        SELECT id, priority FROM assbly_machine_table
        WHERE machine_id = {$draggedTask['machine_id']} AND finished = 0
        ORDER BY priority
    ");
    while ($row = mysqli_fetch_assoc($originalResult)) $originalTasks[] = $row;

    $newTasks = [];
    $newResult = mysqli_query($conn, "
        SELECT id, priority FROM assbly_machine_table
        WHERE machine_id = $newMachineId AND finished = 0
        ORDER BY priority
    ");
    while ($row = mysqli_fetch_assoc($newResult)) $newTasks[] = $row;

    $cases = [];
    $newPriority = 1;
    foreach ($originalTasks as $task) {
        if ($task['id'] != $taskId) {
            $cases[] = "WHEN {$task['id']} THEN $newPriority";
            $newPriority++;
        }
    }
    if (!empty($cases)) {
        $ids = implode(',', array_column($originalTasks, 'id'));
        mysqli_query($conn, "
            UPDATE assbly_machine_table
            SET priority = CASE id " . implode(' ', $cases) . " END
            WHERE id IN ($ids)
        ");
    }

    $insertPriority = ($leftNeighborPriority !== null) ? $leftNeighborPriority + 1 : 1;

    mysqli_query($conn, "
        UPDATE assbly_machine_table
        SET priority = priority + 1
        WHERE machine_id = $newMachineId
          AND finished = 0
          AND priority >= $insertPriority
    ");

    mysqli_query($conn, "
        UPDATE assbly_machine_table SET machine_id = $newMachineId, priority = $insertPriority WHERE id = $taskId
    ");

    if ($draggedTask['machine_id'] != $newMachineId) {
        assbly_fullReschedule($conn, $draggedTask['machine_id']);
        assbly_fullReschedule($conn, $newMachineId);
    } else {
        assbly_fullReschedule($conn, $newMachineId);
    }

    echo json_encode(['status' => 'success', 'message' => 'Task priorities and dates updated successfully']);
    exit;
}

/* =====================================================================
 * add_assbly_break — admin Gantt "Add Break" button
 * ===================================================================== */
else if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'add_assbly_break') {

    $machineId = intval($_REQUEST['machine_id']);
    $duration  = floatval($_REQUEST['duration']);
    $reason    = mysqli_real_escape_string($conn, $_REQUEST['reason']);
    $highestPriority = isset($_REQUEST['highest_priority']) ? intval($_REQUEST['highest_priority']) : 0;

    if ($machineId <= 0 || $duration < 0.5 || $duration > 10) {
        echo json_encode(['status' => 'error', 'message' => 'Invalid input values']);
        exit;
    }

    // FIX: this is the priority the break should actually land at --
    // just ahead of whichever task the caller flagged as currently
    // highest priority. Previously computed and then discarded; the
    // insert always used MAX(priority)+1 (appending to the back).
    $priority = $highestPriority ? max(1, $highestPriority) : 1;

    mysqli_autocommit($conn, false);
    $error = false;

    $result = mysqli_query($conn, "SELECT MAX(end_date) as last_end_date FROM assbly_machine_table WHERE machine_id = $machineId");
    if (!$result) {
        $error = true;
    } else {
        $row = mysqli_fetch_assoc($result);
        $startDate = $row['last_end_date'] ? $row['last_end_date'] : date('Y-m-d H:i:s');
        $endDate   = date('Y-m-d H:i:s', strtotime($startDate) + ($duration * 3600));

        $startDay = date('Y-m-d', strtotime($startDate));
        $endDay   = date('Y-m-d', strtotime($endDate));
        $remainingHours = $duration;
        if ($startDay != $endDay) {
            $endOfFirstDay = date('Y-m-d 23:59:59', strtotime($startDate));
            $firstDayHours = (strtotime($endOfFirstDay) - strtotime($startDate)) / 3600;
            $remainingHours = $duration - $firstDayHours;
        }

        // FIX: scoped to the rows that actually need to move, instead of
        // every row on the machine regardless of position.
        if (!mysqli_query($conn, "
            UPDATE assbly_machine_table SET priority = priority + 1
            WHERE machine_id = $machineId AND priority >= $priority
        ")) {
            $error = true;
        }

        if (!$error) {
            $insertQuery = "INSERT INTO assbly_machine_table
                (machine_id, start_date, end_date, total_hours, remaing_hours, is_break, break_reason, priority)
                VALUES ($machineId, '$startDate', '$endDate', $duration, $remainingHours, 1, '$reason', $priority)";
            if (!mysqli_query($conn, $insertQuery)) {
                $error = true;
            }
        }
    }

    if ($error) {
        mysqli_rollback($conn);
        echo json_encode(['status' => 'error', 'message' => mysqli_error($conn)]);
        mysqli_autocommit($conn, true);
        exit;
    }

    mysqli_commit($conn);
    mysqli_autocommit($conn, true);

    // FIX: previously never called at all for this endpoint.
    assbly_fullReschedule($conn, $machineId);

    echo json_encode(['status' => 'success']);
    exit;
}

/* =====================================================================
 * get_assembly_gantt_rows — HTML row builder for the AJAX-loaded Gantt.
 * Unchanged from original: reads assbly_machine_table joined with
 * work order / manufacture / BOM context and returns rendered rows.
 * ===================================================================== */
else if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'get_assembly_gantt_rows') {

    $currentDateStr = date('Y-m-d');

    $query = "SELECT 
        mmt.machine_id AS task, 
        mmt.id as task_id, 
        wo.work_order_no, 
        mmt.part_id,
        mmt.setup_hours, 
        mmt.priority,
        mmt.total_hours AS hours_to_schedule,
        mmt.total_hours, 
        mmt.work_order_id,
        mmt.product_name,
        mmt.quantity,
        mmt.set_id, 
        won.work_order_name,  
        mmt.shift_ids AS shift_name, 
        DATE(mmt.start_date) AS start_date, 
        DATE(mmt.end_date) AS end_date,
        TIME(mmt.start_date) AS start_time,
        mmt.is_break,
        mmt.break_reason,
        mmt.is_breakdown_affected,
        mmt.breakdown_hours,
        mb.id as breakdown_id,
        mb.breakdown_reason as machine_breakdown_reason,
        m.end_date as manufacture_end_date,
        m.description as manufacture_description,
        m.parent_ids,
        im.part_number as parent_part_number,
        GROUP_CONCAT(DISTINCT wocr.work_order_no ORDER BY wocr.work_order_no SEPARATOR ', ') as customer_order_nos
    FROM assbly_machine_table mmt
    LEFT JOIN work_order wo 
        ON mmt.work_order_id = wo.id
    LEFT JOIN work_order_name won 
        ON mmt.work_order_id = won.work_order_id AND mmt.part_id = won.part_id
    LEFT JOIN machine_breakdown mb 
        ON mmt.machine_id = mb.machine_id AND mb.is_active = 1
    LEFT JOIN (
        SELECT m1.part_id, m1.work_order_id, m1.end_date, m1.description, m1.parent_ids
        FROM manufacture_machine_table m1
        INNER JOIN (
            SELECT part_id, work_order_id, MAX(end_date) as max_end_date
            FROM manufacture_machine_table
            GROUP BY part_id, work_order_id
        ) m2 ON m1.part_id = m2.part_id 
            AND m1.work_order_id = m2.work_order_id 
            AND m1.end_date = m2.max_end_date
    ) m ON mmt.part_id = m.part_id AND mmt.work_order_id = m.work_order_id
    LEFT JOIN item_management im ON m.parent_ids = im.id
    LEFT JOIN work_order_customer_ref_mapping wocr ON mmt.work_order_id = wocr.work_order_id
    WHERE mmt.end_date >= '$currentDateStr'
    GROUP BY 
        mmt.id, mmt.machine_id, wo.work_order_no, mmt.part_id, mmt.setup_hours,
        mmt.priority, mmt.total_hours, mmt.work_order_id, mmt.product_name,
        mmt.quantity, mmt.set_id, won.work_order_name, mmt.shift_ids,
        mmt.start_date, mmt.end_date, mmt.is_break, mmt.break_reason,
        mmt.is_breakdown_affected, mmt.breakdown_hours, mb.id, mb.breakdown_reason,
        m.end_date, m.description, im.part_number, m.parent_ids
    ORDER BY mmt.priority, mmt.machine_id";

    $tasks  = [];
    $result = mysqli_query($conn, $query);
    while ($row = mysqli_fetch_assoc($result)) {
        $row['is_late'] = (
            !empty($row['manufacture_end_date']) &&
            $row['end_date'] > $row['manufacture_end_date']
        );
        $tasks[] = $row;
    }

    $activeBreakdowns = [];
    $bdResult = mysqli_query($conn,
        "SELECT machine_id, breakdown_reason FROM machine_breakdown WHERE is_active = 1");
    while ($bd = mysqli_fetch_assoc($bdResult)) {
        $activeBreakdowns[$bd['machine_id']] = $bd['breakdown_reason'];
    }

    $taskNames    = [];
    $machineQuery = mysqli_query($conn,
        "SELECT id, resource_code FROM station_detail_table WHERE machine_type = 2 AND hide = 0");
    while ($row = mysqli_fetch_assoc($machineQuery)) {
        $taskNames[$row['id']] = $row['resource_code'];
    }

    $colorPalette = [
        '#e6f5f5','#f5e6f5','#e6ffe6','#fff2e6','#f0e6ff',
        '#e6ffff','#ffe6f2','#f5f5e6','#e6f5f5','#f5e6ff',
        '#e6ffec','#fff0e6','#e6f0ff','#ffe6ff','#e6ffe6',
        '#f5e6e6','#e6e6f5','#f5f5e6','#e6f5f5','#f5e6f5'
    ];
    $machineColors = [];
    $colorIndex    = 0;
    foreach ($taskNames as $machineId => $taskName) {
        $machineColors[$machineId] = $colorPalette[$colorIndex % count($colorPalette)];
        $colorIndex++;
    }

    $groupedTasks = [];
    foreach ($tasks as $task) {
        $mid = $task['task'];
        if (!isset($groupedTasks[$mid])) $groupedTasks[$mid] = [];
        $groupedTasks[$mid][] = $task;
    }

    $rowsHtml = '';

    foreach ($taskNames as $machineId => $taskName):

        $rowColor  = $machineColors[$machineId];
        $rowsHtml .= '<div class="gantt-row" data-machine-id="' . $machineId . '" '
                   . 'style="background-color:' . $rowColor . ';">';

        if (!empty($groupedTasks[$machineId])):
            $cumulativePosition = 0;

            foreach ($groupedTasks[$machineId] as $task):
                $taskWidth    = $task['hours_to_schedule'] * 80;
                $leftPosition = $cumulativePosition;
                $cumulativePosition += $taskWidth;

                $part_id                  = (int)$task['part_id'];
                $work_order_id            = $task['work_order_id'];
                $set_id                   = $task['set_id'];
                $parent_ids               = $task['parent_ids'];
                $parent_part_number       = $task['parent_part_number'];
                $setup_hours              = $task['setup_hours'];
                $part_name                = $task['product_name'];
                $quantity                 = $task['quantity'];
                $manufacture_end_date     = $task['manufacture_end_date'];
                $route_detail             = $task['manufacture_description'];
                $comma_customer_order_nos = $task['customer_order_nos'];
                $work_order_name          = $task['work_order_name'] ?? '';

                $dotClass        = 'red-dot-indicator';
                $tooltipContent  = '';
                $allInStock      = true;
                $inventoryStatus = [];

                $invResult = $conn->query(
                    "SELECT im.part_number,
                            COALESCE(i.quantity_in_stock, 0) AS quantity_in_stock
                     FROM bom b
                     LEFT JOIN inventory i ON b.sub_part_id = i.item_id
                     LEFT JOIN item_management im ON b.sub_part_id = im.id
                     WHERE b.main_product_id = $part_id"
                );

                if (!$invResult) {
                    $tooltipContent = 'Error fetching inventory';
                } elseif ($invResult->num_rows > 0) {
                    while ($invRow = $invResult->fetch_assoc()) {
                        $pn  = $invRow['part_number'] ?: 'Unknown Item';
                        $qty = (int)$invRow['quantity_in_stock'];
                        $inventoryStatus[] = "$pn: " . ($qty > 0 ? 'In Stock' : 'Out of Stock')
                                           . " (Qty: $qty)";
                        if ($qty <= 0) $allInStock = false;
                    }
                    $dotClass       = $allInStock ? 'green-dot-indicator' : 'red-dot-indicator';
                    $tooltipContent = "Inventory Status:\n" . implode("\n", $inventoryStatus);
                } else {
                    $tooltipContent = 'No BOM child parts linked.';
                }

                $taskClasses = 'gantt-task';
                if ($task['is_break'])    $taskClasses .= ' break-task';
                elseif ($task['is_late']) $taskClasses .= ' late-task';
                else                      $taskClasses .= ' on-time-task';

                $rowsHtml .= '<div class="' . $taskClasses . '"'
                    . ' draggable="true"'
                    . ' data-task-id="'        . htmlspecialchars($task['task_id'])       . '"'
                    . ' data-priority="'       . htmlspecialchars($task['priority'])      . '"'
                    . ' data-part="'           . htmlspecialchars($part_name)             . '"'
                    . ' data-wo="'             . htmlspecialchars($work_order_name)       . '"'
                    . ' data-work-order="'     . htmlspecialchars($task['work_order_no'] ?? '') . '"'
                    . ' data-part-id="'        . $part_id                                . '"'
                    . ' data-work-order-id="'  . $work_order_id                          . '"'
                    . ' data-hours="'          . $task['hours_to_schedule']              . '"'
                    . ' data-current-machine="'. $machineId                              . '"'
                    . ' style="left:'          . $leftPosition . 'px; width:' . $taskWidth . 'px;">';

                if ($task['is_break']):
                    $rowsHtml .= '<div class="task-content">'
                        . '<strong>BREAK</strong><br/>'
                        . htmlspecialchars($task['break_reason'] ?? '') . '<br/>'
                        . 'Duration: ' . $task['hours_to_schedule'] . 'h'
                        . '</div>';
                else:
                    $rowsHtml .= '<div class="dot-indicator ' . $dotClass . '"'
                        . ' title="' . htmlspecialchars($tooltipContent) . '"></div>';

                    $rowsHtml .= '<div class="task-content" style="font-size:12px;line-height:1.4;">';
                    $rowsHtml .= '<div>'
                        . ($parent_ids == 0
                            ? htmlspecialchars($comma_customer_order_nos ?? '')
                            : htmlspecialchars($parent_part_number ?? ''))
                        . '</div>';
                    $rowsHtml .= '<div>' . htmlspecialchars($work_order_name) . '</div>';
                    $rowsHtml .= '<div>'
                        . '<strong>Item:</strong> ' . htmlspecialchars($part_name)
                        . ' &nbsp;&nbsp;|&nbsp;&nbsp; '
                        . '<strong>Qty:</strong> '  . htmlspecialchars($quantity)
                        . '</div>';
                    $rowsHtml .= '<div><strong>Set Hours:</strong> ' . htmlspecialchars($setup_hours ?? '') . '</div>';

                    if ($task['is_breakdown_affected']):
                        $rowsHtml .= '<div style="color:#ff0000;">'
                            . '<strong>Breakdown Delay: +' . $task['breakdown_hours'] . 'h</strong>'
                            . '</div>';
                    endif;

                    $rowsHtml .= '<div><strong>Desc:</strong> ' . htmlspecialchars($route_detail ?? '') . '</div>';
                    $rowsHtml .= '<div><strong>Due Date:</strong> '
                        . (!empty($manufacture_end_date)
                            ? date('d-M-Y', strtotime($manufacture_end_date))
                            : 'N/A')
                        . '</div>';
                    $rowsHtml .= '</div>'; // .task-content
                endif;

                $rowsHtml .= '<div class="hour-indicator">' . $task['hours_to_schedule'] . 'h';
                if ($task['is_breakdown_affected']):
                    $rowsHtml .= '<br><small>+' . $task['breakdown_hours'] . 'h delay</small>';
                endif;
                $rowsHtml .= '</div>';

                $rowsHtml .= '</div>'; // .gantt-task

            endforeach;
        else:
            $rowsHtml .= '<div class="no-tasks">No tasks scheduled</div>';
        endif;

        $rowsHtml .= '</div>'; // .gantt-row

    endforeach;

    echo json_encode(['success' => true, 'html' => $rowsHtml]);
    exit;
}

/* =====================================================================
 * split_assmbly_work_order — now a thin wrapper around the shared
 * assbly_splitTask(), followed by the reschedule the caller is
 * responsible for.
 * ===================================================================== */
if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'split_assmbly_work_order') {

    $taskId        = intval($_REQUEST['task_id']);
    $splitQuantity = floatval($_REQUEST['split_quantity']);

    if ($taskId <= 0 || $splitQuantity <= 0) {
        echo json_encode(['success' => false, 'message' => 'Invalid input parameters']);
        exit;
    }

    $machineRow = mysqli_fetch_assoc(mysqli_query($conn, "SELECT machine_id FROM assbly_machine_table WHERE id = $taskId"));
    $machineId  = $machineRow ? intval($machineRow['machine_id']) : 0;

    $splitResult = assbly_splitTask($conn, $taskId, $splitQuantity);

    if ($splitResult['success'] && $machineId > 0) {
        assbly_fullReschedule($conn, $machineId);
        $splitResult['message'] = 'Work order split successfully';
    }

    echo json_encode($splitResult);
    exit;
}

else if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'start_machine_breakdown') {
    $machine_id = intval($_REQUEST['machine_id']);
    $breakdown_reason_id = mysqli_real_escape_string($conn, $_REQUEST['breakdown_reason']);
    $now = date('Y-m-d H:i:s');
    $reason_query = "SELECT code FROM keycode_table WHERE id = '$breakdown_reason_id'";
    $reason_result = mysqli_query($conn, $reason_query);

    if ($reason_result && mysqli_num_rows($reason_result) > 0) {
        $reason_data = mysqli_fetch_assoc($reason_result);
        $reason_text = $reason_data['code'];
    } else {
        $reason_text = 'Unknown Reason';
    }
    // Stop any ongoing breakdowns before starting a new one
    mysqli_query($conn, "UPDATE machine_breakdown 
                         SET is_active = 0, breakdown_end = '$now', 
                             breakdown_hours = TIMESTAMPDIFF(MINUTE, breakdown_start, '$now') / 60,
                             updated_at = '$now' 
                         WHERE machine_id = $machine_id AND is_active = 1");

    // Start new breakdown
    $sql = "INSERT INTO machine_breakdown (machine_id, breakdown_start, breakdown_reason, is_active, created_at, updated_at)
            VALUES ($machine_id, '$now', '$reason_text', 1, '$now', '$now')";
    mysqli_query($conn, $sql);

    // Mark affected work orders
    assbly_markBreakdownAffectedWorkOrders($conn, $machine_id, $now, null);

    // FIX: mirror into the tablet's source-of-truth table — previously
    // a breakdown started here was invisible to assbly_isMachineInBreakdown().
    mysqli_query($conn, "
        INSERT INTO assbly_machine_breakdown_log
        (work_order_id, part_id, machine_id, engineer_id, assbly_machine_table_id, breakdown_reason,
         breakdown_duration, ok_count_at_breakdown, remaining_quantity, status, created_at)
        VALUES (0, 0, $machine_id, 0, 0, '" . mysqli_real_escape_string($conn, $reason_text) . "', 0, 0, 0, 'active', '$now')
    ");

    echo json_encode(['status' => 'success']);
    exit;
    
} else if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'stop_machine_breakdown') {
    $machine_id = intval($_POST['machine_id']);
    $now = date('Y-m-d H:i:s');

    // Stop the breakdown
    $sql = "UPDATE machine_breakdown 
            SET is_active = 0, breakdown_end = '$now',
                breakdown_hours = TIMESTAMPDIFF(MINUTE, breakdown_start, '$now') / 60,
                updated_at = '$now'
            WHERE machine_id = $machine_id AND is_active = 1";
    mysqli_query($conn, $sql);

    // Reset breakdown_affected status for all work orders of this machine
    mysqli_query($conn, "
        UPDATE assbly_machine_table 
        SET is_breakdown_affected = 0 
        WHERE machine_id = $machine_id AND is_breakdown_affected = 1
    ");

    // FIX: mirror the closure into assbly_machine_breakdown_log too.
    $lastLog = mysqli_fetch_assoc(mysqli_query($conn, "
        SELECT * FROM assbly_machine_breakdown_log WHERE machine_id = $machine_id AND status = 'active' ORDER BY id DESC LIMIT 1
    "));
    if ($lastLog) {
        mysqli_query($conn, "
            INSERT INTO assbly_machine_breakdown_log
            (work_order_id, part_id, machine_id, engineer_id, assbly_machine_table_id, breakdown_reason,
             breakdown_duration, ok_count_at_breakdown, remaining_quantity, status, created_at)
            VALUES ({$lastLog['work_order_id']}, {$lastLog['part_id']}, $machine_id, {$lastLog['engineer_id']}, {$lastLog['assbly_machine_table_id']},
                    {$lastLog['breakdown_reason']}, {$lastLog['breakdown_duration']}, {$lastLog['ok_count_at_breakdown']},
                    {$lastLog['remaining_quantity']}, 'completed', '$now')
        ");
    }

    // FIX: this endpoint never rescheduled at all before.
    assbly_fullReschedule($conn, $machine_id);

    echo json_encode(['status' => 'success']);
    exit;

} else if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'get_machine_breakdown_status') {
    // FIX: reads assbly_machine_breakdown_log now, consistent with the
    // shared source of truth (was reading the generic machine_breakdown
    // table, which admin-triggered breakdowns wrote to but the tablet
    // never checked).
    $sql = "SELECT ab.*, sd.resource_code AS machine_name
            FROM assbly_machine_breakdown_log ab
            LEFT JOIN station_detail_table sd ON ab.machine_id = sd.id
            ORDER BY ab.created_at DESC LIMIT 10";
    $res = mysqli_query($conn, $sql);

    $data = [];
    while ($row = mysqli_fetch_assoc($res)) {
        $data[] = $row;
    }

    echo json_encode(['status' => 'success', 'data' => $data]);
    exit;
    
} else if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'get_assmbly_task_details') {

    $task_id = mysqli_real_escape_string($conn, $_REQUEST['task_id']);
    $work_order_id = mysqli_real_escape_string($conn, $_REQUEST['work_order_id']);
    $part_id = mysqli_real_escape_string($conn, $_REQUEST['part_id']);
    $machine_id = mysqli_real_escape_string($conn, $_REQUEST['machine_id']);
    

    $query = "SELECT 
    mmt.machine_id AS task, 
    mmt.id as task_id, 
    wo.work_order_no, 
    mmt.part_id,
    mmt.setup_hours,  
    mmt.priority,
    mmt.total_hours AS hours_to_schedule,
    mmt.total_hours, 
    mmt.work_order_id,
    mmt.product_name,
    mmt.quantity,
    mmt.set_id, 
    won.work_order_name, 
    mmt.shift_ids AS shift_name, 
    DATE(mmt.start_date) AS start_date, 
    DATE(mmt.end_date) AS end_date,
    TIME(mmt.start_date) AS start_time,
    mmt.is_break,
    mmt.break_reason,
    mmt.is_breakdown_affected,
    mmt.breakdown_hours,
    mb.id as breakdown_id,
    mb.breakdown_reason as machine_breakdown_reason,
    m.end_date as manufacture_end_date,
    m.description as manufacture_description,
    im.part_number as parent_part_number,
    GROUP_CONCAT(DISTINCT wocr.work_order_no ORDER BY wocr.work_order_no SEPARATOR ', ') as customer_order_nos
FROM 
    assbly_machine_table mmt
LEFT JOIN 
    work_order wo ON mmt.work_order_id = wo.id
LEFT JOIN 
    work_order_name won ON mmt.work_order_id = won.work_order_id AND mmt.part_id = won.part_id
LEFT JOIN 
    machine_breakdown mb ON mmt.machine_id = mb.machine_id AND mb.is_active = 1
LEFT JOIN (
    SELECT 
        m1.part_id, 
        m1.work_order_id, 
        m1.end_date, 
        m1.description, 
        m1.parent_ids
    FROM manufacture_machine_table m1
    INNER JOIN (
        SELECT 
            part_id, 
            work_order_id, 
            MAX(end_date) as max_end_date
        FROM manufacture_machine_table
        GROUP BY part_id, work_order_id
    ) m2 ON m1.part_id = m2.part_id 
        AND m1.work_order_id = m2.work_order_id 
        AND m1.end_date = m2.max_end_date
) m ON mmt.part_id = m.part_id 
    AND mmt.work_order_id = m.work_order_id
LEFT JOIN 
    item_management im ON m.parent_ids = im.id
LEFT JOIN 
    work_order_customer_ref_mapping wocr ON mmt.work_order_id = wocr.work_order_id
WHERE mmt.id = '$task_id'
    LIMIT 1
";
    $result = mysqli_query($conn, $query);
    
    if ($result && mysqli_num_rows($result) > 0) {
        $data = mysqli_fetch_assoc($result);

        if ($data['set_id'] != 0) {
            $route_query = "SELECT route_desc FROM set_route_details WHERE set_id = '{$data['set_id']}' LIMIT 1";
        } else {
            $route_query = "SELECT route_desc FROM route_details WHERE item_id = '{$data['part_id']}' LIMIT 1";
        }
        $route_result = mysqli_query($conn, $route_query);
        if ($route_result && mysqli_num_rows($route_result) > 0) {
            $route_data = mysqli_fetch_assoc($route_result);
            $data['route_desc'] = $route_data['route_desc'];
        } else {
            $data['route_desc'] = '-';
        }

        // FIX: was comparing $row['manufacture_end_date']/$row['end_date']
        // — $row was never set in this handler (copy-paste leftover; the
        // fetched row is $data). empty() on an undefined variable is
        // always true, so is_late could never become true. Now compares
        // $data against itself correctly.
        $data['is_late'] = (
            !empty($data['manufacture_end_date']) &&
            $data['end_date'] > $data['manufacture_end_date']
        );

        // FIX: renamed locals (ppQuery/ppResult/ppRow) so this lookup no
        // longer reuses $query/$result/$row from the main query above —
        // harmless as originally written since those were done with, but
        // kept distinct for clarity and to avoid future breakage if code
        // is inserted between the two blocks.
        $ppQuery = "
            SELECT 
                customer_reff,
                GROUP_CONCAT(DISTINCT RefSalesCode ORDER BY RefSalesCode SEPARATOR ', ') AS RefSalesCode
            FROM production_planning
            WHERE work_order_id = " . intval($work_order_id);

        $ppResult = mysqli_query($conn, $ppQuery);
        $ppRow = mysqli_fetch_assoc($ppResult);
        $customer_reff = $ppRow['customer_reff'] ?? '';

        $data['customer_code'] = utility::getTableFieldById("client_management", "customer_code", "id", $customer_reff);
        $data['RefSalesCode'] = $ppRow['RefSalesCode'] ?? '';

        echo json_encode([
            'success' => true,
            'data' => $data
        ]);
    } else {
        echo json_encode([
            'success' => false,
            'message' => 'Task not found'
        ]);
    }
    exit;
}

else if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'update_assmbly_task') {

    $task_id = mysqli_real_escape_string($conn, $_POST['task_id']);
    $priority = mysqli_real_escape_string($conn, $_POST['priority']);
    $machine_id = mysqli_real_escape_string($conn, $_POST['machine_id']);
    $setup_hours = mysqli_real_escape_string($conn, $_POST['setup_hours']);
    $total_hours = mysqli_real_escape_string($conn, $_POST['total_hours']);
    $start_date = mysqli_real_escape_string($conn, $_POST['start_date']);
    $quantity = mysqli_real_escape_string($conn, $_POST['quantity']);
    
    $update_query = "UPDATE assbly_machine_table SET 
        priority = '$priority',
        machine_id = '$machine_id',
        setup_hours = '$setup_hours',
        total_hours = '$total_hours',
        start_date = '$start_date',
        quantity = '$quantity',
        updated_at = NOW()
    WHERE id = '$task_id'";
    
    if (mysqli_query($conn, $update_query)) {
        $recalculate_query = "SELECT id, priority FROM assbly_machine_table 
                             WHERE machine_id = '$machine_id' AND finished = 0 
                             ORDER BY priority";
        $result = mysqli_query($conn, $recalculate_query);
        
        $new_priority = 1;
        while ($row = mysqli_fetch_assoc($result)) {
            mysqli_query($conn, "UPDATE assbly_machine_table SET priority = $new_priority WHERE id = {$row['id']}");
            $new_priority++;
        }

        assbly_fullReschedule($conn, $machine_id);
        
        echo json_encode([
            'success' => true,
            'message' => 'Work order updated successfully'
        ]);
    } else {
        echo json_encode([
            'success' => false,
            'message' => 'Failed to update work order: ' . mysqli_error($conn)
        ]);
    }
    exit;
}
else if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'delete_assmbly_task') {

    $task_id = mysqli_real_escape_string($conn, $_REQUEST['task_id']);
    $work_order_id = mysqli_real_escape_string($conn, $_REQUEST['work_order_id']);
    $part_id = mysqli_real_escape_string($conn, $_REQUEST['part_id']);
    
    $machine_query = "SELECT machine_id FROM assbly_machine_table WHERE id = '$task_id' LIMIT 1";
    $machine_result = mysqli_query($conn, $machine_query);
    $machine_data = mysqli_fetch_assoc($machine_result);
    $machine_id = $machine_data['machine_id'];
    
    $delete_query = "DELETE FROM assbly_machine_table WHERE id = '$task_id'";
    
    if (mysqli_query($conn, $delete_query)) {
		$updateQuery = "
			UPDATE manufacture_machine_table 
			SET in_scheduler_check = 0 
			WHERE work_order_id = '$work_order_id'
			  AND part_id = '$part_id'
		";

		$conn->query($updateQuery);
        assbly_fullReschedule($conn, $machine_id);
        
        echo json_encode([
            'success' => true,
            'message' => 'Work order deleted successfully'
        ]);
    } else {
        echo json_encode([
            'success' => false,
            'message' => 'Failed to delete work order: ' . mysqli_error($conn)
        ]);
    }
    exit;
}
else if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'toggle_machine_visibility') {
    $machine_id = intval($_REQUEST['machine_id']);
    $hide = intval($_REQUEST['hide']);
    
    if ($machine_id <= 0) {
        echo json_encode(['status' => 'error', 'message' => 'Invalid machine ID']);
        exit;
    }
    
    if ($hide == 1) {
        $today = date('Y-m-d');

        $taskResult = mysqli_query($conn,
            "SELECT id, work_order_id, part_id 
             FROM assbly_machine_table 
             WHERE machine_id = $machine_id 
               AND DATE(end_date) >= '$today'"
        );

        if ($taskResult) {
            while ($task = mysqli_fetch_assoc($taskResult)) {
                $workOrderId = intval($task['work_order_id']);
                $partId      = intval($task['part_id']);

                mysqli_query($conn,
                    "UPDATE manufacture_machine_table 
                     SET in_scheduler_check = 0 
                     WHERE work_order_id = $workOrderId 
                       AND part_id = $partId"
                );
            }
        }

        mysqli_query($conn,
            "DELETE FROM assbly_machine_table 
             WHERE machine_id = $machine_id 
               AND DATE(end_date) >= '$today'"
        );
    }

    $update_query = "UPDATE station_detail_table 
                     SET hide = $hide 
                     WHERE id = $machine_id AND machine_type = 2";
    
    if (mysqli_query($conn, $update_query)) {
        $action_text = $hide ? 'hidden' : 'unhidden';
        echo json_encode([
            'status'     => 'success',
            'message'    => "Machine $action_text successfully",
            'machine_id' => $machine_id,
            'hide'       => $hide
        ]);
    } else {
        echo json_encode([
            'status'  => 'error',
            'message' => 'Database error: ' . mysqli_error($conn)
        ]);
    }
    exit;
}

else if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'get_hidden_machines') {
    $query = "SELECT id, resource_code, resource_description 
              FROM station_detail_table 
              WHERE machine_type = 2 AND hide = 1 
              ORDER BY resource_code";
    
    $result = mysqli_query($conn, $query);
    
    if ($result) {
        $hidden_machines = [];
        while ($row = mysqli_fetch_assoc($result)) {
            $hidden_machines[] = [
                'id' => $row['id'],
                'resource_code' => $row['resource_code'],
                'resource_name' => $row['resource_description']
            ];
        }
        
        echo json_encode([
            'status' => 'success',
            'data' => $hidden_machines,
            'count' => count($hidden_machines)
        ]);
    } else {
        echo json_encode([
            'status' => 'error',
            'message' => 'Database error: ' . mysqli_error($conn)
        ]);
    }
    exit;
}

else if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'bulk_toggle_machine_visibility') {
    $machine_ids_json = $_REQUEST['machine_ids'] ?? '';
    $hide = intval($_REQUEST['hide']);
    
    $machine_ids = json_decode($machine_ids_json, true);
    
    if (empty($machine_ids) || !is_array($machine_ids)) {
        echo json_encode(['status' => 'error', 'message' => 'No machines selected or invalid data']);
        exit;
    }
    
    $sanitized_ids = array_filter(array_map('intval', $machine_ids), function($id) {
        return $id > 0;
    });
    
    if (empty($sanitized_ids)) {
        echo json_encode(['status' => 'error', 'message' => 'No valid machine IDs provided']);
        exit;
    }
    
    mysqli_autocommit($conn, false);
    $error = false;
    
    if ($hide == 1) {
        $today      = date('Y-m-d');
        $ids_string = implode(',', $sanitized_ids);

        $taskResult = mysqli_query($conn,
            "SELECT id, work_order_id, part_id 
             FROM assbly_machine_table 
             WHERE machine_id IN ($ids_string) 
               AND DATE(end_date) >= '$today'"
        );

        if ($taskResult) {
            while ($task = mysqli_fetch_assoc($taskResult)) {
                $workOrderId = intval($task['work_order_id']);
                $partId      = intval($task['part_id']);

                if (!mysqli_query($conn,
                    "UPDATE manufacture_machine_table 
                     SET in_scheduler_check = 0 
                     WHERE work_order_id = $workOrderId 
                       AND part_id = $partId"
                )) { $error = true; break; }
            }
        }

        if (!$error) {
            if (!mysqli_query($conn,
                "DELETE FROM assbly_machine_table 
                 WHERE machine_id IN ($ids_string) 
                   AND DATE(end_date) >= '$today'"
            )) { $error = true; }
        }
    }

    if (!$error) {
        $ids_string    = implode(',', $sanitized_ids);
        $update_query  = "UPDATE station_detail_table 
                          SET hide = $hide 
                          WHERE id IN ($ids_string) AND machine_type = 2";

        if (mysqli_query($conn, $update_query)) {
            $affected_rows = mysqli_affected_rows($conn);
            mysqli_commit($conn);
            $action_text = $hide ? 'hidden' : 'shown';
            echo json_encode([
                'status'         => 'success',
                'message'        => "$affected_rows machine(s) $action_text successfully",
                'affected_count' => $affected_rows,
                'hide'           => $hide
            ]);
        } else {
            $error = true;
        }
    }

    if ($error) {
        mysqli_rollback($conn);
        echo json_encode(['status' => 'error', 'message' => mysqli_error($conn)]);
    }
    
    mysqli_autocommit($conn, true);
    exit;
}
else if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'get_all_assembly_machines') {
    $query = "SELECT id, resource_code, resource_description, hide 
              FROM station_detail_table 
              WHERE machine_type = 2 
              ORDER BY resource_code";
    
    $result = mysqli_query($conn, $query);
    
    if ($result) {
        $machines = [];
        while ($row = mysqli_fetch_assoc($result)) {
            $machines[] = [
                'id' => $row['id'],
                'resource_code' => $row['resource_code'],
                'resource_description' => $row['resource_description'],
                'hide' => $row['hide']
            ];
        }
        
        echo json_encode([
            'status' => 'success',
            'data' => $machines,
            'count' => count($machines)
        ]);
    } else {
        echo json_encode([
            'status' => 'error',
            'message' => 'Database error: ' . mysqli_error($conn)
        ]);
    }
    exit;
}

else if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'get_breakdown_status') {

    $machineId = intval($_REQUEST['machine_id'] ?? 0);

    // FIX: reads assbly_machine_breakdown_log, consistent with the
    // shared source of truth used elsewhere in this file.
    $query = "
        SELECT *
        FROM assbly_machine_breakdown_log
        WHERE machine_id = $machineId
        AND status = 'active'
        ORDER BY created_at DESC, id DESC
        LIMIT 1
    ";

    $result = mysqli_query($conn, $query);

    if ($result && mysqli_num_rows($result) > 0) {
        $row = mysqli_fetch_assoc($result);
        echo json_encode(['status' => 'active', 'data' => $row]);
    } else {
        echo json_encode(['status' => 'inactive']);
    }

    exit;
}
?>