<?php

$operations = [];

function processOrderHybrid($product_ids, $order_quantities, $shift_ids, $conn, $required_date, $work_order_id, $simulateOnly, $set_ids, $depth = 0, $max_depth = 10, $parent_ids = []) {
    global $operations;
    global $work_order_id;

    // Initialize an array to track all sub-parts needed across all products
    $all_sub_parts = [];
    $all_can_fulfill = true;

    // Process each product in the array
    for ($i = 0; $i < count($product_ids); $i++) {
        $product_id = $product_ids[$i];
        $quantity_needed = $order_quantities[$i];
        $current_parent_id = $parent_ids;

        $product_code = "Level" . str_pad(($depth - 1) * 10, 2, "0", STR_PAD_LEFT);
        $operations[] = [
            'product_code' => $product_code,
            'product_id' => $product_id,
            'parent_ids' => is_array($current_parent_id) ? array_unique($current_parent_id) : [], // Track all parents // Track all parents as array
            'operation' => "Processing $product_code for Product ID $product_id. Required Date: $required_date.",
            'qty' => $quantity_needed,
            'process_type' => 55,
            'required_date' => $required_date
        ];

        // Check inventory for this product
        $query = "SELECT quantity_in_stock FROM inventory WHERE item_id = $product_id";
        $result = $conn->query($query);
        $query_p = "SELECT part_number FROM item_management WHERE id = $product_id";
        $result_p = $conn->query($query_p);

        if ($result_p && $result_p->num_rows > 0) { 
            $row_p = $result_p->fetch_assoc();
            $p_name = $row_p['part_number']; 
        }

        if ($result->num_rows > 0) {
            $row = $result->fetch_assoc();
            $available_qty = $row['quantity_in_stock'];
            if ($available_qty > 0) {
                $used_qty = min($quantity_needed, $available_qty);
                if ($simulateOnly == 1) {
                    $conn->query("UPDATE inventory SET quantity_in_stock = quantity_in_stock - $used_qty WHERE item_id = $product_id");
                }
                $operations[] = [
                    'product_code' => $product_code,
                    'product_name' => $p_name,
                    'product_id' => $product_id,
                    'parent_ids' => $current_parent_id ? [$current_parent_id] : [], // Track all parents
                    'operation' => "Fulfilled from inventory for Product ID $product_id. Used: $used_qty, Remaining in inventory: " . ($available_qty - $used_qty) . ".",
                    'qty' => $used_qty,
                    'process_type' => 12,
                    'required_date' => $required_date
                ];

                $quantity_needed -= $used_qty;
            }

            if ($quantity_needed <= 0) {
                continue; // Fully fulfilled from inventory
            }
        }

        // Calculate route time and schedule work
        $route_data = calculateRouteTime($product_id, $quantity_needed, $conn, $set_ids);
        //$route_time_minutes = $route_data['route_time']; // in minutes
        //$route_time_hours = ceil($route_time_minutes / 60);
        $route_time_hours = $route_data['route_time'];
        $machine_id = $route_data['machine'];
         
        $query_machine = "SELECT id, resource_code FROM station_detail_table WHERE id = '$machine_id'"; 
        $result_machine = $conn->query($query_machine);
        if ($result_machine && $result_machine->num_rows > 0) {
            while ($row = $result_machine->fetch_assoc()) {
                $machine = $row['resource_code']; 
            }
        }
         
        $work_schedule = arrangeWorkAcrossDaysWithStartDate($route_time_hours, $required_date, $shift_ids, $conn);
        $start_date = $work_schedule['start_date'];
        $start_date = date('Y-m-d', strtotime($start_date));
        $days_allocation = $work_schedule['days_allocation'];
    //echo $route_time_hours;
	//	echo "<br>";
        if ($route_time_hours > 0) {
            $operations[] = [
                'product_code' => $product_code,
                'product_name' => $p_name,
                'product_id' => $product_id,
                'parent_ids' =>array_unique($current_parent_id), // Track all parents
                'operation' => "Route time: " . round($route_time_hours, 2) . " hours (100% efficiency), on machine $machine.",
                'qty' => $quantity_needed,
                'process_type' => 6,
                'machine' => $machine_id,
                'Start_Date' => $start_date,
				'total_time' => $route_time_hours,
                'required_date' => $required_date
            ];
        }

      
       /* foreach ($days_allocation as $day) {
            $day_name = date('l', strtotime("Sunday +{$day['day']} days"));
            $operations[] = [
                'product_code' => $product_code,
                'product_id' => $product_id,
                'parent_ids' => $current_parent_id ? [$current_parent_id] : [], // Track all parents
                'operation' => "Allocated {$day['hours_allocated']} hours of work on {$day['date']} ({$day_name}).",
                'qty' => $quantity_needed,
                'process_type' => 7,
                'required_date' => $required_date
            ];
        }*/
		foreach ($days_allocation as $index => $day) {
			$day_name = date('l', strtotime("Sunday +{$day['day']} days"));

			// Set highlight value based on the index
			$highlight = null;
			if ($index === 0) {
				$highlight = 121;
			} elseif ($index === 2) {
				$highlight = 131;
			}

			$operations[] = [
				'product_code' => $product_code,
				'product_id' => $product_id,
				'parent_ids' => is_array($current_parent_id) ? array_unique($current_parent_id) : [], // Track all parents
				'operation' => "Allocated {$day['hours_allocated']} hours of work on {$day['date']} ({$day_name}).",
				'qty' => $quantity_needed,
				'process_type' => 7,
				'required_date' => $required_date,
				'highlight' => $highlight,  // Store the highlight value if it exists
				'allocated_dates' => $day['date']   // Store the highlight value if it exists
			];
		}

        // Get BOM for this product
        $query = "SELECT sub_part_id, sub_part_name, quantity_required, type FROM bom WHERE main_product_id = $product_id";
        $bom_parts = $conn->query($query);

        if ($bom_parts->num_rows > 0) {
            if ($depth >= $max_depth) {
                // Fall back to stack processing if we reach max depth
                $all_can_fulfill = $all_can_fulfill && processOrderStack($product_id, $quantity_needed, $conn);
                continue;
            }

            while ($bom = $bom_parts->fetch_assoc()) {
                $sub_part_id = $bom['sub_part_id'];
                $sub_part_name = $bom['sub_part_name'];
                $sub_quantity_needed = $quantity_needed * $bom['quantity_required'];
                $type = $bom['type'];
                $sub_required_date = date('Y-m-d', strtotime($start_date));

                // Track this sub-part in our consolidated list
                if (!isset($all_sub_parts[$sub_part_id])) {
                    $all_sub_parts[$sub_part_id] = [
                        'name' => $sub_part_name,
                        'quantity' => 0,
                        'type' => $type,
                        'required_date' => $sub_required_date,
                        'parent_ids' => [],
                        'product_ids' => []
                    ];
                }

                // Accumulate quantities and track the latest required date
                $all_sub_parts[$sub_part_id]['quantity'] += $sub_quantity_needed;
                if (strtotime($sub_required_date) < strtotime($all_sub_parts[$sub_part_id]['required_date'])) {
                    $all_sub_parts[$sub_part_id]['required_date'] = $sub_required_date;
                }
                // Track parent and product relationships
                if ($current_parent_id) {
                    $all_sub_parts[$sub_part_id]['parent_ids'][] = $current_parent_id;
                }
                $all_sub_parts[$sub_part_id]['parent_ids'][] = $product_id; // Add current product as parent
                $all_sub_parts[$sub_part_id]['product_ids'][] = $product_id;
            }
        } else {
            // No BOM - need to purchase this product
            if ($simulateOnly == 1) {
               // $conn->query("INSERT INTO purchase_list (item_id, quantity_requested, required_date, work_order_id) VALUES ($product_id, $quantity_needed, '$required_date', $work_order_id)");
            }
            $operations[] = [
                'product_code' => $product_code,
                'product_id' => $product_id,
                'parent_ids' => is_array($current_parent_id) ? array_unique($current_parent_id) : [], // Track all parents
                'operation' => "Raw Matrial $product_code (Quantity: $quantity_needed, Required Date: $required_date).",
                'qty' => $quantity_needed,
                'process_type' => 44,
                'required_date' => $required_date
            ];
            $all_can_fulfill = false;
        }
    }

    // Now process all the accumulated sub-parts
    foreach ($all_sub_parts as $sub_part_id => $sub_part_data) {
        $sub_product_code = "Level" . str_pad(($depth - 2) * 10, 2, "0", STR_PAD_LEFT);
        $unique_parent_ids = array_unique($sub_part_data['parent_ids']);
        
        $operations[] = [
            'product_code' => $sub_product_code,
            'product_id' => $sub_part_id,
            'parent_ids' => $unique_parent_ids,
            'operation' => "Processing $sub_product_code for Sub-Part ID $sub_part_id (Name: {$sub_part_data['name']}, Type: {$sub_part_data['type']}, Qty: {$sub_part_data['quantity']}, Required Date: {$sub_part_data['required_date']}).",
            'qty' => $sub_part_data['quantity'],
            'process_type' => 5,
            'required_date' => $sub_part_data['required_date']
        ];

        if ($sub_part_data['type'] === "Bought In") {
            // Check inventory for bought-in parts
            $query = "SELECT quantity_in_stock FROM inventory WHERE item_id = $sub_part_id";
            $result = $conn->query($query);

            if ($result->num_rows > 0) {
                $row = $result->fetch_assoc();
                $available_qty = $row['quantity_in_stock'];
                if ($available_qty > 0) {
                    $used_qty = min($sub_part_data['quantity'], $available_qty);
                    if ($simulateOnly == 1) {
                        $conn->query("UPDATE inventory SET quantity_in_stock = quantity_in_stock - $used_qty WHERE item_id = $sub_part_id");
                    }
                    $operations[] = [
                        'product_code' => $sub_product_code,
                        'product_name' => $sub_part_data['name'],
                        'product_id' => $sub_part_id,
                        'parent_ids' => $unique_parent_ids, // Show all unique parent IDs
                        'operation' => "Fulfilled from inventory for Sub-Part ID $sub_part_id. Used: $used_qty, Remaining in inventory: " . ($available_qty - $used_qty) . ".",
                        'qty' => $used_qty,
                        'process_type' => 12,
                        'required_date' => $sub_part_data['required_date']
                    ];
                    $sub_part_data['quantity'] -= $used_qty;
                }
            }

            if ($sub_part_data['quantity'] > 0) {
                if ($simulateOnly == 1) {
                   // $query = "INSERT INTO purchase_list (item_id, quantity_requested, required_date, work_order_id) VALUES ($sub_part_id, {$sub_part_data['quantity']}, '{$sub_part_data['required_date']}', $work_order_id)";
                    //$conn->query($query);
                }
                $operations[] = [
                    'product_code' => $sub_product_code,
                    'product_name' => $sub_part_data['name'],
                    'product_id' => $sub_part_id,
                    'parent_ids' => $unique_parent_ids, // Show all unique parent IDs
                    'operation' => "Raw Matrial {$sub_part_data['quantity']} units of Sub-Part ID $sub_part_id.",
                    'qty' => $sub_part_data['quantity'],
                    'process_type' => 4,
                    'required_date' => $sub_part_data['required_date']
                ];
                $all_can_fulfill = false;
            }
        } elseif ($sub_part_data['type'] === "Manufactured" || $sub_part_data['type'] === "Assembly") {
            // Recursively process manufactured/assembly parts
            $result = processOrderHybrid(
                [$sub_part_id], 
                [$sub_part_data['quantity']], 
                $shift_ids, 
                $conn, 
                $sub_part_data['required_date'], 
                $work_order_id, 
                $simulateOnly, 
				$set_ids,
                $depth - 1, 
                $max_depth, 
                $unique_parent_ids // Pass all parent IDs to next level
            );
            $all_can_fulfill = $all_can_fulfill && $result;
        }
    }

    return $all_can_fulfill;
}












function arrangeWorkAcrossDaysWithStartDate($total_hours, $required_date, $shift_ids, $conn) {
    $working_hours = calculateShiftHours($shift_ids, $conn);
    $remaining_hours = $total_hours;
    $current_date = new DateTime($required_date);

    $query_h = "SELECT holiday_date FROM admin_holidays";  
    $result_h = $conn->query($query_h);
    $holidays = [];

    if ($result_h && $result_h->num_rows > 0) {
        while ($row = $result_h->fetch_assoc()) {
            $holidays[] = $row['holiday_date']; 
        }
    }

    $days_allocation = [];

    // Allocate actual required hours
    while ($remaining_hours > 0) {
        $current_day = (int) $current_date->format('w');
        $current_date_string = $current_date->format('Y-m-d');

        if (!in_array($current_date_string, $holidays, true) && $working_hours[$current_day] > 0) {
            $hours_for_day = $working_hours[$current_day];

            if ($remaining_hours <= $hours_for_day) {
                $days_allocation[] = [
                    'date' => $current_date_string,
                    'day' => $current_day,
                    'hours_allocated' => $remaining_hours
                ];
                $remaining_hours = 0;
            } else {
                $days_allocation[] = [
                    'date' => $current_date_string,
                    'day' => $current_day,
                    'hours_allocated' => $hours_for_day
                ];
                $remaining_hours -= $hours_for_day;
            }
        }

        $current_date->modify('-1 day');
    }

    // Add 2 extra working days
    $extra_days_added = 0;
    while ($extra_days_added < 2) {
        $current_day = (int) $current_date->format('w');
        $current_date_string = $current_date->format('Y-m-d');

        if (!in_array($current_date_string, $holidays, true) && $working_hours[$current_day] > 0) {
            $days_allocation[] = [
                'date' => $current_date_string,
                'day' => $current_day,
                'hours_allocated' => $working_hours[$current_day]
            ];
            $extra_days_added++;
        }

        $current_date->modify('-1 day');
    }

    return [
        'start_date' => $current_date->format('Y-m-d'),
        'days_allocation' => array_reverse($days_allocation)
    ];
}

function calculateShiftHours($ids, $conn) {
    $working_hours = [
        0 => 0, // Sunday
        1 => 0, // Monday
        2 => 0, // Tuesday
        3 => 0, // Wednesday
        4 => 0, // Thursday
        5 => 0, // Friday
        6 => 0  // Saturday
    ];

    foreach ($ids as $id) {
        $query = "SELECT day_shifts, hours FROM working_hours WHERE id = $id"; 
        $result = $conn->query($query);

        if ($result && $result->num_rows > 0) {
            while ($row = $result->fetch_assoc()) {
                $day_shift = $row['day_shifts'];
                $hours = $row['hours'];
				//echo "<br>";
                if (isset($working_hours[$day_shift])) {
                    $working_hours[$day_shift] += $hours;
                }
            }
        }
    }

    return $working_hours;
	print_r($working_hours);
}

/*function calculateRouteTime($product_id, $quantity_needed, $conn, $set_ids) {
	
    $query = "SELECT operation_time, parts_per_operation, machine_high_priority FROM route_details WHERE item_id = $product_id";
    $result = $conn->query($query);

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

        $machine = $row['machine_high_priority'];
        $operation_time = !empty($row['operation_time']) ? (float)$row['operation_time'] : 1;
        $parts_per_operation = (!empty($row['parts_per_operation']) && $row['parts_per_operation'] > 0) 
            ? (float)$row['parts_per_operation'] 
            : 1;
        $quantity_needed = !empty($quantity_needed) ? (int)$quantity_needed : 1;

        return [
            'route_time' => ($operation_time / $parts_per_operation) * $quantity_needed,
            'machine' => $machine
        ];
    }

    return [
        'route_time' => 0,
        'machine' => null
    ]; 
}*/


function calculateRouteTime($product_id, $quantity_needed, $conn, $set_ids) {
    $setId = null;
    foreach ($set_ids as $set) {
        if ($set['setItemId'] == $product_id) {
            $setId = $set['setId'];
            break;
        }
    }

    if ($setId !== null) {
        $query = "SELECT operation_time, parts_per_operation, machine_high_priority FROM set_route_details WHERE set_id = $setId";
    } else {
        $query = "SELECT operation_time, parts_per_operation, machine_high_priority FROM route_details WHERE item_id = $product_id";
    }

    $result = $conn->query($query);

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

        $machine = $row['machine_high_priority'];
        $operation_time = !empty($row['operation_time']) ? (float)$row['operation_time'] : 1;
        $parts_per_operation = (!empty($row['parts_per_operation']) && $row['parts_per_operation'] > 0) 
            ? (float)$row['parts_per_operation'] 
            : 1;
        $quantity_needed = !empty($quantity_needed) ? (int)$quantity_needed : 1;

        return [
            'route_time' => ($operation_time / $parts_per_operation) * $quantity_needed,
            'machine' => $machine
        ];
    }*/
	if ($result && $result->num_rows > 0) {
		$row = $result->fetch_assoc();

		$machine = $row['machine_high_priority'];

		// Convert operation_time (HH:MM:SS) to total seconds
		if (!empty($row['operation_time'])) {
			list($h, $m, $s) = explode(":", $row['operation_time']);
			$operation_time = ($h * 3600) + ($m * 60) + $s; // in seconds
		} else {
			$operation_time = 1; // fallback
		}

		$parts_per_operation = (!empty($row['parts_per_operation']) && $row['parts_per_operation'] > 0) 
			? (float)$row['parts_per_operation'] 
			: 1;

		$quantity_needed = !empty($quantity_needed) ? (int)$quantity_needed : 1;

		// route_time in seconds
		$route_time_seconds = ($operation_time / $parts_per_operation) * $quantity_needed;

		// Convert to hours
		$route_time_hours = $route_time_seconds / 3600;

		return [
			'route_time' => $route_time_hours, // in hours
			'machine' => $machine
		];
	}


    return [
        'route_time' => 0,
        'machine' => null
    ]; 
}








function processOrderStack($product_id, $quantity_needed, $conn) {
    global $operations;

    $stack = [];
    array_push($stack, [
        'product_id' => $product_id,
        'quantity_needed' => $quantity_needed,
        'depth' => 0,
        'required_date' => date('Y-m-d'),
    ]);

    while (!empty($stack)) {
        $current = array_pop($stack);
        $current_product_id = $current['product_id'];
        $current_quantity_needed = $current['quantity_needed'];
        $depth = $current['depth'];
        $required_date = $current['required_date'];

        $current_product_code = "Level" . str_pad(($depth + 1) * 10, 2, "0", STR_PAD_LEFT);

        $operations[] = [
            'product_code' => $current_product_code,
            'product_id' => $current_product_id,
            'operation' => "Processing $current_product_code for Product ID $current_product_id. Required Date: $required_date.",
            'qty' => $current_quantity_needed,
            'process_type' => 888,
            'required_date' => $required_date
        ];

        // Check inventory
        $query = "SELECT quantity_in_stock FROM inventory WHERE item_id = $current_product_id";
        $result = $conn->query($query);

        if ($result->num_rows > 0) {
            $row = $result->fetch_assoc();
            if ($row['quantity_in_stock'] >= $current_quantity_needed) {
                $conn->query("UPDATE inventory SET quantity_in_stock = quantity_in_stock - $current_quantity_needed WHERE item_id = $current_product_id");
                $operations[] = [
                    'product_code' => $current_product_code,
                    'operation' => "Order fulfilled from inventory for Product ID $current_product_id. Remaining quantity: " . ($row['quantity_in_stock'] - $current_quantity_needed) . ".",
                    'qty' => $current_quantity_needed,
                    'process_type' => 888,
                    'required_date' => $required_date
                ];
                continue;
            } else {
                $operations[] = [
                    'product_code' => $current_product_code,
                    'operation' => "Insufficient inventory for Product ID $current_product_id. Needed: $current_quantity_needed, Available: {$row['quantity_in_stock']}.",
                    'qty' => $current_quantity_needed,
                    'process_type' => 888,
                    'required_date' => $required_date
                ];
            }
        }

        // Process BOM
        $query = "SELECT sub_part_id, sub_part_name, quantity_required, type FROM bom WHERE main_product_id = $current_product_id";
        $bom_parts = $conn->query($query);

        if ($bom_parts->num_rows > 0) {
            while ($bom = $bom_parts->fetch_assoc()) {
                $sub_part_id = $bom['sub_part_id'];
                $sub_part_name = $bom['sub_part_name'];
                $sub_quantity_needed = $current_quantity_needed * $bom['quantity_required'];
                $type = $bom['type'];

                $sub_product_code = "Level" . str_pad(($depth + 2) * 10, 2, "0", STR_PAD_LEFT);
                $sub_required_date = date('Y-m-d', strtotime($required_date . " -2 days"));

                $operations[] = [
                    'product_code' => $sub_product_code,
                    'operation' => "Processing $sub_product_code for Sub-Part ID $sub_part_id (Name: $sub_part_name, Type: $type, Qty: $sub_quantity_needed, Required Date: $sub_required_date).",
                    'qty' => $sub_quantity_needed,
                    'process_type' => 888,
                    'required_date' => $sub_required_date
                ];

                if ($type === "Bought In") {
                    $query = "SELECT quantity_in_stock FROM inventory WHERE item_id = $sub_part_id";
                    $result = $conn->query($query);

                    if ($result->num_rows > 0) {
                        $row = $result->fetch_assoc();
                        if ($row['quantity_in_stock'] >= $sub_quantity_needed) {
                            $conn->query("UPDATE inventory SET quantity_in_stock = quantity_in_stock - $sub_quantity_needed WHERE item_id = $sub_part_id");
                            $operations[] = [
                                'product_code' => $sub_product_code,
                                'operation' => "Order fulfilled from inventory for Sub-Part ID $sub_part_id. Remaining quantity: " . ($row['quantity_in_stock'] - $sub_quantity_needed) . ".",
                                'qty' => $sub_quantity_needed,
                                'process_type' => 888,
                                'required_date' => $sub_required_date
                            ];
                            continue;
                        }
                    }

                   // $conn->query("INSERT INTO purchase_list (item_id, quantity_requested) VALUES ($sub_part_id, $sub_quantity_needed)");
                    $operations[] = [
                        'product_code' => $sub_product_code,
                        'operation' => "Raw Matrial  $sub_part_id.",
                        'qty' => $sub_quantity_needed,
                        'process_type' => 888,
                        'required_date' => $sub_required_date
                    ];
                } elseif ($type === "Manufactured" || $type === "Assembly") {
                    array_push($stack, [
                        'product_id' => $sub_part_id,
                        'quantity_needed' => $sub_quantity_needed,
                        'depth' => $depth + 1,
                        'required_date' => $sub_required_date
                    ]);
                }
            }
        } else {
           // $conn->query("INSERT INTO purchase_list (item_id, quantity_requested) VALUES ($current_product_id, $current_quantity_needed)");
            $operations[] = [
                'product_code' => $current_product_code,
                'operation' => "Raw Matrial $current_product_id.",
                'qty' => $current_quantity_needed,
                'process_type' => 4,
                'required_date' => $required_date
            ];
        }
    }

    return true;
}

?>
 