<?php
// api_packing_list_handler.php - Verarbeitet AJAX-Anfragen von der Packlisten-Bearbeitungsseite
// FINALE, STABILE VERSION 14: Implementiert eine robuste "State-Sync"-Logik.

if (session_status() == PHP_SESSION_NONE) {
    session_start();
}
header('Content-Type: application/json');

// Error handling...
function handle_fatal_error() {
    $error = error_get_last();
    if ($error !== null && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR])) {
        if (headers_sent()) { return; }
        http_response_code(500);
        echo json_encode(['error' => 'Kritischer Serverfehler: ' . $error['message']]);
        exit;
    }
}
register_shutdown_function('handle_fatal_error');
function handle_all_errors($errno, $errstr, $errfile, $errline) {
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
}
set_error_handler('handle_all_errors');

$conn = null;
try {
    if (!isset($_SESSION['user_id'])) {
        throw new Exception('Nicht angemeldet', 403);
    }
    require_once 'db_connect.php';
    $data = json_decode(file_get_contents('php://input'), true);
    if (json_last_error() !== JSON_ERROR_NONE) {
        throw new Exception('Ungültige Anfrage: JSON konnte nicht dekodiert werden.', 400);
    }
    $action = $data['action'] ?? '';
    $packing_list_id = intval($data['packing_list_id'] ?? 0);
    if ($packing_list_id === 0) {
        throw new Exception("Keine Packlisten-ID angegeben.", 400);
    }
    if (!user_can_edit_list($conn, $packing_list_id, $_SESSION['user_id'])) {
        throw new Exception('Zugriff verweigert.', 403);
    }

    $conn->begin_transaction();
    
    switch ($action) {
        case 'sync_list':
            $items_from_frontend = $data['list'];
            
            $old_quantities = [];
            $stmt_get_old = $conn->prepare("SELECT id, quantity FROM packing_list_items WHERE packing_list_id = ?");
            $stmt_get_old->bind_param("i", $packing_list_id);
            $stmt_get_old->execute();
            $result_old = $stmt_get_old->get_result();
            while($row = $result_old->fetch_assoc()) {
                $old_quantities[$row['id']] = $row['quantity'];
            }
            $stmt_get_old->close();

            // FIX: Erst alle Eltern-Beziehungen lösen, um Foreign-Key-Fehler beim Löschen zu vermeiden
            $stmt_unlink_parents = $conn->prepare("UPDATE packing_list_items SET parent_packing_list_item_id = NULL WHERE packing_list_id = ?");
            $stmt_unlink_parents->bind_param("i", $packing_list_id);
            $stmt_unlink_parents->execute();
            $stmt_unlink_parents->close();

            $stmt_delete = $conn->prepare("DELETE FROM packing_list_items WHERE packing_list_id = ?");
            $stmt_delete->bind_param("i", $packing_list_id);
            if(!$stmt_delete->execute()) throw new Exception("Fehler beim Löschen der alten Liste.");
            $stmt_delete->close();
            
            $stmt_insert = $conn->prepare("INSERT INTO packing_list_items (packing_list_id, article_id, quantity, carrier_user_id, order_index, parent_packing_list_item_id, backpack_id, backpack_compartment_id, name) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");

            $id_map = []; // Mappt temporäre Frontend-IDs auf neue DB-IDs
            foreach ($items_from_frontend as $index => $item_data) {
                $pli_id_frontend = $item_data['pli_id'];
                $article_id = intval($item_data['article_id']);
                $carrier_id = ($item_data['carrier_id'] === 'null' || $item_data['carrier_id'] === null) ? NULL : intval($item_data['carrier_id']);
                
                // New fields
                $backpack_id = !empty($item_data['backpack_id']) ? intval($item_data['backpack_id']) : NULL;
                $backpack_compartment_id = !empty($item_data['backpack_compartment_id']) ? intval($item_data['backpack_compartment_id']) : NULL;
                // For normal items, name is NULL (fetched from articles). For containers, name might be set if needed, but usually containers are created via edit_packing_list_details.
                // If this sync receives items that are containers (backpack_id set), we might not have 'name' in payload if it came from DOM.
                // Actually, the containers are created in 'edit_details'. Sync just re-orders them. 
                // We need to preserve the 'name' if it exists in the old record, or pass it from frontend. 
                // Simplified: If article_id is 0 or null, we might need a name. 
                // BUT: The frontend sends 'article_id' from dataset. Containers created in backend have article_id=0 (or NULL).
                // Let's assume for now we just persist what we get. If article_id is missing, we rely on DB to handle it (it's nullable?).
                // Wait, the previous INSERT required article_id. We need to change article_id column to be NULLable or handle 0.
                
                $article_id_val = ($article_id > 0) ? $article_id : NULL;
                $name_val = NULL; // Only needed if we were passing names from frontend, which we aren't really for existing items.
                
                // Re-fetch name for containers if we are re-inserting them?
                // The sync deletes and re-inserts. If we don't provide a name for a container (which has no article_id), it will be lost!
                // We MUST fetch the name from the frontend payload or the old DB record.
                // Let's adding 'name' to payload in frontend is best.
                
                // WICHTIG: Parent-ID muss bereits gemappt sein. Das Frontend MUSS Eltern VOR Kindern senden.
                // Die rekursive "traverse"-Funktion im JS garantiert dies (Pre-Order Traversal).
                $parent_pli_id = isset($item_data['parent_pli_id']) && isset($id_map[$item_data['parent_pli_id']]) ? $id_map[$item_data['parent_pli_id']] : null;
                
                $quantity = isset($old_quantities[$pli_id_frontend]) ? intval($old_quantities[$pli_id_frontend]) : 1;
                if ($quantity < 1) $quantity = 1;
                
                $stmt_insert->bind_param("iiiiiiiis", $packing_list_id, $article_id_val, $quantity, $carrier_id, $index, $parent_pli_id, $backpack_id, $backpack_compartment_id, $name_val);
                if(!$stmt_insert->execute()) throw new Exception("Fehler beim Einfügen von Artikel " . $article_id . ": " . $stmt_insert->error);
                $new_db_id = $conn->insert_id;
                $id_map[$pli_id_frontend] = $new_db_id;

                if (!empty($item_data['is_new']) && !empty($item_data['include_children'])) {
                    $stmt_children = $conn->prepare("SELECT id FROM articles WHERE parent_article_id = ?");
                    $stmt_children->bind_param("i", $article_id);
                    $stmt_children->execute();
                    $result_children = $stmt_children->get_result();
                    $child_items = $result_children->fetch_all(MYSQLI_ASSOC);
                    $stmt_children->close();

                    if (!empty($child_items)) {
                        $temp_index = $index;
                        // Schiebe alle nachfolgenden Elemente nach hinten
                        $stmt_shift = $conn->prepare("UPDATE packing_list_items SET order_index = order_index + ? WHERE packing_list_id = ? AND order_index > ?");
                        $count_children = count($child_items);
                        $stmt_shift->bind_param("iii", $count_children, $packing_list_id, $temp_index);
                        $stmt_shift->execute();
                        $stmt_shift->close();

                        foreach ($child_items as $child) {
                            $temp_index++;
                            // Child items are normal items
                            $null_val1 = NULL;
                            $null_val2 = NULL;
                            $null_val3 = NULL;
                            $qty_one = 1;
                            $stmt_insert->bind_param("iiiiiiiis", $packing_list_id, $child['id'], $qty_one, $carrier_id, $temp_index, $new_db_id, $null_val1, $null_val2, $null_val3);
                            if(!$stmt_insert->execute()) throw new Exception("Fehler beim Einfügen von Kind-Artikel " . $child['id']);
                        }
                    }
                }
            }
            $stmt_insert->close();
            
            // Post-Fix: Restore names for containers from Backpack tables if they were lost because we didn't send them from frontend.
            // Actually, better to just UPDATE them based on IDs after insertion.
            // Update Root Names
            $conn->query("UPDATE packing_list_items pli JOIN backpacks b ON pli.backpack_id = b.id SET pli.name = CONCAT('Rucksack: ', b.name) WHERE pli.packing_list_id = $packing_list_id AND pli.backpack_id IS NOT NULL");
            // Update Compartment Names
            $conn->query("UPDATE packing_list_items pli JOIN backpack_compartments bc ON pli.backpack_compartment_id = bc.id SET pli.name = bc.name WHERE pli.packing_list_id = $packing_list_id AND pli.backpack_compartment_id IS NOT NULL");
            
            break;

        case 'delete_item':
            $item_id = intval($data['item_id']);
            
            // Recursive Delete Logic
            $ids_to_delete = [$item_id];
            $i = 0;
            while($i < count($ids_to_delete)) {
                $current_parent = $ids_to_delete[$i];
                $stmt_children = $conn->prepare("SELECT id FROM packing_list_items WHERE parent_packing_list_item_id = ?");
                $stmt_children->bind_param("i", $current_parent);
                $stmt_children->execute();
                $result = $stmt_children->get_result();
                while($row = $result->fetch_assoc()) {
                    $ids_to_delete[] = $row['id'];
                }
                $stmt_children->close();
                $i++;
            }
            
            $in_query = implode(',', array_fill(0, count($ids_to_delete), '?'));
            $types = str_repeat('i', count($ids_to_delete));
            $stmt_delete = $conn->prepare("DELETE FROM packing_list_items WHERE id IN ($in_query) AND packing_list_id = ?");
            $delete_params = array_merge($ids_to_delete, [$packing_list_id]);
            $delete_types = $types . 'i';
            $stmt_delete->bind_param($delete_types, ...$delete_params);
            $stmt_delete->execute();
            $stmt_delete->close();
            break;

        case 'adjust_table_quantity':
            $article_id = intval($data['article_id']);
            $delta = intval($data['delta']); // 1 or -1
            $include_children = !empty($data['include_children']);
            
            function adjust_single($conn, $packing_list_id, $art_id, $delta) {
                $stmt_find = $conn->prepare("SELECT id, quantity FROM packing_list_items WHERE packing_list_id = ? AND article_id = ? AND carrier_user_id IS NULL AND backpack_id IS NULL AND backpack_compartment_id IS NULL AND parent_packing_list_item_id IS NULL LIMIT 1");
                $stmt_find->bind_param("ii", $packing_list_id, $art_id);
                $stmt_find->execute();
                $res = $stmt_find->get_result();
                if ($row = $res->fetch_assoc()) {
                    $new_quantity = $row['quantity'] + $delta;
                    if ($new_quantity > 0) {
                        $stmt_update = $conn->prepare("UPDATE packing_list_items SET quantity = ? WHERE id = ?");
                        $stmt_update->bind_param("ii", $new_quantity, $row['id']);
                        $stmt_update->execute();
                        $stmt_update->close();
                    } else {
                        $stmt_del = $conn->prepare("DELETE FROM packing_list_items WHERE id = ?");
                        $stmt_del->bind_param("i", $row['id']);
                        $stmt_del->execute();
                        $stmt_del->close();
                    }
                } else {
                    if ($delta > 0) {
                        $idx_res = $conn->query("SELECT MAX(order_index) as max_idx FROM packing_list_items WHERE packing_list_id = $packing_list_id");
                        $next_idx = ($idx_res->fetch_assoc()['max_idx'] ?? 0) + 1;
                        $stmt_insert = $conn->prepare("INSERT INTO packing_list_items (packing_list_id, article_id, quantity, order_index) VALUES (?, ?, ?, ?)");
                        $stmt_insert->bind_param("iiii", $packing_list_id, $art_id, $delta, $next_idx);
                        $stmt_insert->execute();
                        $stmt_insert->close();
                    }
                }
                $stmt_find->close();
            }

            adjust_single($conn, $packing_list_id, $article_id, $delta);

            if ($include_children && $delta > 0) {
                $stmt_children = $conn->prepare("SELECT id FROM articles WHERE parent_article_id = ?");
                $stmt_children->bind_param("i", $article_id);
                $stmt_children->execute();
                $res_child = $stmt_children->get_result();
                while($child = $res_child->fetch_assoc()) {
                    adjust_single($conn, $packing_list_id, $child['id'], $delta);
                }
                $stmt_children->close();
            }
            break;

        case 'update_quantity':
            $item_id = intval($data['item_id']);
            $quantity = intval($data['quantity']);
            if ($quantity > 0) {
                $stmt = $conn->prepare("UPDATE packing_list_items SET quantity = ? WHERE id = ?");
                $stmt->bind_param("ii", $quantity, $item_id); $stmt->execute(); $stmt->close();
                $conn->commit(); echo json_encode(get_all_items($conn, $packing_list_id)); exit;
            } else { throw new Exception('Ungültige Mengenangabe.'); }
            break;
            
        case 'get_items':
            // Just returns the current state (handled at the end of script)
            break;
            
        default:
            throw new Exception('Unbekannte Aktion angefordert.', 400);
    }
    $conn->commit();
    echo json_encode(get_all_items($conn, $packing_list_id));
} catch (Exception $e) {
    // Versuch Rollback, falls Transaktion aktiv war
    if ($conn) {
        try { $conn->rollback(); } catch (Throwable $t) {}
    }
    file_put_contents(__DIR__ . '/api_error.log', date('Y-m-d H:i:s') . ' - ERROR: ' . $e->getMessage() . "\n" . $e->getTraceAsString() . "\n\n", FILE_APPEND);
    http_response_code(500);
    echo json_encode(['error' => $e->getMessage()]);
} finally {
    if ($conn && $conn instanceof mysqli) $conn->close();
}

function user_can_edit_list($conn, $packing_list_id, $user_id) {
    if (empty($packing_list_id) || empty($user_id)) return false;
    $stmt_household = $conn->prepare("SELECT household_id FROM users WHERE id = ?");
    $stmt_household->bind_param("i", $user_id);
    $stmt_household->execute();
    $household_id = $stmt_household->get_result()->fetch_assoc()['household_id'] ?? null;
    $stmt_household->close();
    $stmt_list = $conn->prepare("SELECT user_id, household_id FROM packing_lists WHERE id = ?");
    $stmt_list->bind_param("i", $packing_list_id);
    $stmt_list->execute();
    $list_data_result = $stmt_list->get_result();
    $stmt_list->close();
    if ($list_data_result->num_rows === 0) return false;
    $list_data = $list_data_result->fetch_assoc();
    if ($list_data['user_id'] == $user_id) return true;
    if (!empty($list_data['household_id']) && $list_data['household_id'] == $household_id) return true;
    return false;
}

function get_all_items($conn, $packing_list_id) {
    $sql = "SELECT 
                pli.id, 
                pli.article_id, 
                pli.quantity, 
                pli.parent_packing_list_item_id, 
                pli.carrier_user_id, 
                pli.backpack_id, 
                pli.backpack_compartment_id, 
                COALESCE(
                    a.name, 
                    bc.name,
                    CASE WHEN b.name IS NOT NULL THEN CONCAT('Rucksack: ', b.name) ELSE NULL END,
                    pli.name
                ) as name, 
                a.weight_grams, 
                a.product_designation, 
                a.consumable, 
                m.name as manufacturer_name 
            FROM packing_list_items pli 
            LEFT JOIN articles a ON pli.article_id = a.id 
            LEFT JOIN manufacturers m ON a.manufacturer_id = m.id 
            LEFT JOIN backpacks b ON pli.backpack_id = b.id
            LEFT JOIN backpack_compartments bc ON pli.backpack_compartment_id = bc.id
            WHERE pli.packing_list_id = ? 
            ORDER BY pli.order_index ASC, pli.id ASC";
            
    $stmt = $conn->prepare($sql);
    $stmt->bind_param("i", $packing_list_id);
    $stmt->execute();
    $result = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
    $stmt->close();
    return $result;
}
?>
