<?php
require_once __DIR__ . '/../helpers/auth.php';
require_once __DIR__ . '/../helpers/audit.php';
require_once __DIR__ . '/../helpers/barcode_utils.php';
require_once __DIR__ . '/../helpers/inventory.php';

require_role(['admin', 'staff']);

$pdo = db();
$user = current_user();
$title = 'Products - Caerus Tech IMS';

function h(?string $value): string
{
    return htmlspecialchars((string)($value ?? ''), ENT_QUOTES, 'UTF-8');
}
function post_str(string $key): string
{
    return trim((string)($_POST[$key] ?? ''));
}
function post_int(string $key): int
{
    return (int)($_POST[$key] ?? 0);
}
function post_float(string $key): float
{
    $value = str_replace(',', '.', trim((string)($_POST[$key] ?? '0')));
    return (float)$value;
}
function product_exists_by_barcode(PDO $pdo, string $barcode, ?int $excludeId = null): bool
{
    if ($excludeId) {
        $stmt = $pdo->prepare('SELECT id FROM products WHERE barcode_value = :barcode AND id <> :id LIMIT 1');
        $stmt->execute([':barcode' => $barcode, ':id' => $excludeId]);
    } else {
        $stmt = $pdo->prepare('SELECT id FROM products WHERE barcode_value = :barcode LIMIT 1');
        $stmt->execute([':barcode' => $barcode]);
    }
    return (bool)$stmt->fetchColumn();
}
function product_exists_by_sku(PDO $pdo, string $sku, ?int $excludeId = null): bool
{
    if ($excludeId) {
        $stmt = $pdo->prepare('SELECT id FROM products WHERE sku = :sku AND id <> :id LIMIT 1');
        $stmt->execute([':sku' => $sku, ':id' => $excludeId]);
    } else {
        $stmt = $pdo->prepare('SELECT id FROM products WHERE sku = :sku LIMIT 1');
        $stmt->execute([':sku' => $sku]);
    }
    return (bool)$stmt->fetchColumn();
}
function status_pill_class(string $status): string
{
    return match (strtoupper($status)) {
        'LOW' => 'status-pill status-low',
        'OK' => 'status-pill status-ok',
        default => 'status-pill status-neutral',
    };
}
function format_money(float $amount): string
{
    return '€' . number_format($amount, 2);
}
function column_exists(PDO $pdo, string $table, string $column): bool
{
    try {
        $stmt = $pdo->prepare("
            SELECT COUNT(*)
            FROM INFORMATION_SCHEMA.COLUMNS
            WHERE TABLE_SCHEMA = DATABASE()
              AND TABLE_NAME = :table
              AND COLUMN_NAME = :column
        ");
        $stmt->execute([
            ':table' => $table,
            ':column' => $column,
        ]);
        return (int)$stmt->fetchColumn() > 0;
    } catch (Throwable $e) {
        return false;
    }
}
function ensure_product_photo_column(PDO $pdo): void
{
    static $checked = false;
    if ($checked) {
        return;
    }
    $checked = true;

    if (!column_exists($pdo, 'products', 'photo_path')) {
        $pdo->exec("ALTER TABLE products ADD COLUMN photo_path VARCHAR(255) NULL AFTER description");
    }
}
function public_products_upload_dir(): string
{
    return dirname(__DIR__) . '/uploads/products';
}
function ensure_product_upload_dir(): string
{
    $dir = public_products_upload_dir();
    if (!is_dir($dir)) {
        mkdir($dir, 0775, true);
    }

    $indexPath = $dir . '/index.php';
    if (!file_exists($indexPath)) {
        @file_put_contents($indexPath, "<?php http_response_code(403); exit;\n");
    }

    return $dir;
}
function normalize_product_photo_path(?string $path): string
{
    $path = trim((string)$path);
    if ($path === '') {
        return '';
    }
    $path = str_replace('\\', '/', $path);
    $path = preg_replace('#/+#', '/', $path);
    return ltrim($path, '/');
}
function product_photo_url(?string $path): string
{
    $path = normalize_product_photo_path($path);
    if ($path === '') {
        return '';
    }
    return '../' . $path;
}
function delete_product_photo_file(?string $path): void
{
    $path = normalize_product_photo_path($path);
    if ($path === '') {
        return;
    }

    $absolute = dirname(__DIR__) . '/' . $path;
    $uploadsRoot = realpath(dirname(__DIR__) . '/uploads');
    $realFile = realpath($absolute);

    if ($realFile && $uploadsRoot && str_starts_with($realFile, $uploadsRoot) && is_file($realFile)) {
        @unlink($realFile);
    }
}
function handle_product_photo_upload(string $fieldName, array &$errors, ?string $existingPath = null): ?string
{
    if (!isset($_FILES[$fieldName]) || !is_array($_FILES[$fieldName])) {
        return $existingPath;
    }

    $file = $_FILES[$fieldName];
    $errorCode = (int)($file['error'] ?? UPLOAD_ERR_NO_FILE);

    if ($errorCode === UPLOAD_ERR_NO_FILE) {
        return $existingPath;
    }

    if ($errorCode !== UPLOAD_ERR_OK) {
        $errors[] = 'Failed to upload product photo.';
        return $existingPath;
    }

    $tmpName = (string)($file['tmp_name'] ?? '');
    if ($tmpName === '' || !is_uploaded_file($tmpName)) {
        $errors[] = 'Invalid uploaded product photo.';
        return $existingPath;
    }

    $maxBytes = 5 * 1024 * 1024;
    $size = (int)($file['size'] ?? 0);
    if ($size <= 0 || $size > $maxBytes) {
        $errors[] = 'Product photo must be 5MB or smaller.';
        return $existingPath;
    }

    $mime = null;
    if (function_exists('finfo_open')) {
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        if ($finfo) {
            $mime = finfo_file($finfo, $tmpName) ?: null;
            finfo_close($finfo);
        }
    }

    $allowed = [
        'image/jpeg' => 'jpg',
        'image/png' => 'png',
        'image/webp' => 'webp',
        'image/gif' => 'gif',
    ];

    if (!$mime || !isset($allowed[$mime])) {
        $errors[] = 'Product photo must be JPG, PNG, WEBP, or GIF.';
        return $existingPath;
    }

    ensure_product_upload_dir();

    $extension = $allowed[$mime];
    $filename = 'product_' . date('Ymd_His') . '_' . bin2hex(random_bytes(8)) . '.' . $extension;
    $relativePath = 'uploads/products/' . $filename;
    $absolutePath = dirname(__DIR__) . '/' . $relativePath;

    if (!move_uploaded_file($tmpName, $absolutePath)) {
        $errors[] = 'Failed to save uploaded product photo.';
        return $existingPath;
    }

    if ($existingPath && normalize_product_photo_path($existingPath) !== normalize_product_photo_path($relativePath)) {
        delete_product_photo_file($existingPath);
    }

    return $relativePath;
}
function load_categories_map(PDO $pdo): array
{
    $hasParentId = column_exists($pdo, 'product_categories', 'parent_id');

    if ($hasParentId) {
        $sql = 'SELECT id, name, parent_id FROM product_categories ORDER BY name ASC';
    } else {
        $sql = 'SELECT id, name, NULL AS parent_id FROM product_categories ORDER BY name ASC';
    }

    $rows = $pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);
    $map = [];
    foreach ($rows as $row) {
        $id = (int)$row['id'];
        $map[$id] = [
            'id' => $id,
            'name' => (string)$row['name'],
            'parent_id' => isset($row['parent_id']) && $row['parent_id'] !== null ? (int)$row['parent_id'] : null,
        ];
    }
    return $map;
}
function build_category_label(int $categoryId, array $categoriesMap, array &$cache = [], array $trail = []): string
{
    if ($categoryId <= 0 || !isset($categoriesMap[$categoryId])) {
        return '';
    }
    if (isset($cache[$categoryId])) {
        return $cache[$categoryId];
    }
    if (in_array($categoryId, $trail, true)) {
        return $categoriesMap[$categoryId]['name'] ?? '';
    }

    $category = $categoriesMap[$categoryId];
    $parentId = $category['parent_id'];

    if ($parentId && isset($categoriesMap[$parentId])) {
        $parentLabel = build_category_label($parentId, $categoriesMap, $cache, array_merge($trail, [$categoryId]));
        $label = $parentLabel !== ''
            ? ($parentLabel . ' → ' . $category['name'])
            : $category['name'];
    } else {
        $label = $category['name'];
    }

    $cache[$categoryId] = $label;
    return $label;
}
function category_depth(int $categoryId, array $categoriesMap, array $trail = []): int
{
    if ($categoryId <= 0 || !isset($categoriesMap[$categoryId])) {
        return 0;
    }
    if (in_array($categoryId, $trail, true)) {
        return 0;
    }

    $parentId = $categoriesMap[$categoryId]['parent_id'] ?? null;
    if ($parentId && isset($categoriesMap[$parentId])) {
        return 1 + category_depth($parentId, $categoriesMap, array_merge($trail, [$categoryId]));
    }
    return 0;
}
function sort_categories_for_dropdown(array $categoriesMap): array
{
    $items = array_values($categoriesMap);

    usort($items, static function (array $a, array $b) use ($categoriesMap): int {
        $depthA = category_depth((int)$a['id'], $categoriesMap);
        $depthB = category_depth((int)$b['id'], $categoriesMap);

        if ($depthA !== $depthB) {
            return $depthA <=> $depthB;
        }

        return strcasecmp((string)$a['name'], (string)$b['name']);
    });

    return $items;
}

ensure_product_photo_column($pdo);
ensure_product_upload_dir();

$errors = [];
$success = '';
$q = trim((string)($_GET['q'] ?? ''));

if (($_GET['ajax'] ?? '') === 'lookup_barcode') {
    header('Content-Type: application/json; charset=utf-8');

    $barcode = normalize_barcode_value(trim((string)($_GET['barcode'] ?? '')));
    if ($barcode === '') {
        http_response_code(400);
        echo json_encode(['ok' => false, 'message' => 'Barcode is required.']);
        exit;
    }

    $hasCategoryParentForLookup = column_exists($pdo, 'product_categories', 'parent_id');
    $lookupSql = '
        SELECT
            p.*,
            c.name AS category_name,
            ' . ($hasCategoryParentForLookup ? 'c.parent_id' : 'NULL') . ' AS category_parent_id,
            s.name AS supplier_name,
            COALESCE(stock_summary.current_stock, p.quantity_on_hand, 0) AS current_stock
        FROM products p
        LEFT JOIN product_categories c ON c.id = p.category_id
        LEFT JOIN suppliers s ON s.id = p.supplier_id
        LEFT JOIN (
            SELECT m.product_id, ' . inventory_stock_expression('m') . ' AS current_stock
            FROM inventory_movements m
            GROUP BY m.product_id
        ) stock_summary ON stock_summary.product_id = p.id
        WHERE p.barcode_value = :barcode
        LIMIT 1
    ';

    $lookupStmt = $pdo->prepare($lookupSql);
    $lookupStmt->execute([':barcode' => $barcode]);
    $product = $lookupStmt->fetch(PDO::FETCH_ASSOC);

    if (!$product) {
        http_response_code(404);
        echo json_encode(['ok' => false, 'message' => 'No product found for this barcode.']);
        exit;
    }

    $lookupCategoriesMap = load_categories_map($pdo);
    $lookupCategoryLabelCache = [];
    $categoryId = (int)($product['category_id'] ?? 0);
    $categoryLabel = $categoryId > 0 ? build_category_label($categoryId, $lookupCategoriesMap, $lookupCategoryLabelCache) : '';
    $currentStock = (int)($product['current_stock'] ?? 0);
    $reorderLevel = (int)($product['reorder_level'] ?? 0);
    $stockState = ($reorderLevel > 0 && $currentStock <= $reorderLevel) ? 'LOW' : 'OK';

    echo json_encode([
        'ok' => true,
        'product' => [
            'id' => (int)$product['id'],
            'name' => (string)$product['name'],
            'sku' => (string)($product['sku'] ?? ''),
            'barcode_value' => (string)($product['barcode_value'] ?? ''),
            'barcode_generated' => (int)($product['barcode_generated'] ?? 0),
            'barcode_type' => (string)($product['barcode_type'] ?? ''),
            'category' => $categoryLabel,
            'supplier' => (string)($product['supplier_name'] ?? ''),
            'description' => (string)($product['description'] ?? ''),
            'unit' => (string)($product['unit'] ?? ''),
            'cost_price' => (float)($product['cost_price'] ?? 0),
            'sell_price' => (float)($product['sell_price'] ?? 0),
            'reorder_level' => $reorderLevel,
            'current_stock' => $currentStock,
            'is_active' => (int)($product['is_active'] ?? 0),
            'stock_state' => $stockState,
            'photo_path' => (string)($product['photo_path'] ?? ''),
            'photo_url' => product_photo_url($product['photo_path'] ?? ''),
        ],
    ], JSON_UNESCAPED_SLASHES);
    exit;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $action = post_str('action');

    if ($action === 'add') {
        $name = post_str('name');
        $sku = post_str('sku');
        $category_id = post_int('category_id') ?: null;
        $supplier_id = post_int('supplier_id') ?: null;
        $description = post_str('description');
        $unit = post_str('unit') ?: 'pcs';
        $cost_price = post_float('cost_price');
        $sell_price = post_float('sell_price');
        $reorder_level = max(0, post_int('reorder_level'));
        $is_active = post_int('is_active') ? 1 : 0;
        $barcode_value = normalize_barcode_value(post_str('barcode_value'));
        $photo_path = null;

        if ($name === '') {
            $errors[] = 'Product name is required.';
        }
        if ($sku === '') {
            $errors[] = 'SKU is required.';
        }
        if ($sku !== '' && product_exists_by_sku($pdo, $sku)) {
            $errors[] = 'SKU already exists.';
        }

        if ($barcode_value !== '') {
            if (!is_supported_product_barcode($barcode_value)) {
                $errors[] = 'Barcode must be numeric and at least 12 digits. Leave blank to auto-generate.';
            } elseif (product_exists_by_barcode($pdo, $barcode_value)) {
                $errors[] = 'Barcode already exists.';
            }
        }

        $photo_path = handle_product_photo_upload('photo', $errors);

        if (!$errors) {
            try {
                $pdo->beginTransaction();

                $stmt = $pdo->prepare('
                    INSERT INTO products
                        (category_id, supplier_id, sku, name, description, photo_path, unit, cost_price, sell_price, reorder_level, is_active, barcode_value, barcode_type, barcode_generated, quantity_on_hand)
                    VALUES
                        (:category_id, :supplier_id, :sku, :name, :description, :photo_path, :unit, :cost_price, :sell_price, :reorder_level, :is_active, NULL, :barcode_type, 0, 0)
                ');
                $stmt->execute([
                    ':category_id' => $category_id,
                    ':supplier_id' => $supplier_id,
                    ':sku' => $sku,
                    ':name' => $name,
                    ':description' => $description !== '' ? $description : null,
                    ':photo_path' => $photo_path ?: null,
                    ':unit' => $unit,
                    ':cost_price' => $cost_price,
                    ':sell_price' => $sell_price,
                    ':reorder_level' => $reorder_level,
                    ':is_active' => $is_active,
                    ':barcode_type' => 'CUSTOM',
                ]);

                $newId = (int)$pdo->lastInsertId();
                $generated = 0;
                if ($barcode_value === '') {
                    $barcode_value = generate_upc_a_from_product_id($newId, '200');
                    $generated = 1;
                }

                $barcodeType = detect_barcode_type($barcode_value, $generated === 1);

                $barcodeUpdate = $pdo->prepare('UPDATE products SET barcode_value = :barcode_value, barcode_generated = :generated, barcode_type = :barcode_type WHERE id = :id');
                $barcodeUpdate->execute([
                    ':barcode_value' => $barcode_value,
                    ':generated' => $generated,
                    ':barcode_type' => $barcodeType,
                    ':id' => $newId,
                ]);

                inventory_sync_product_quantity($pdo, $newId);
                $pdo->commit();

                audit_log('CREATE_PRODUCT', 'products', (string)$newId, json_encode([
                    'sku' => $sku,
                    'name' => $name,
                    'barcode_value' => $barcode_value,
                    'photo_path' => $photo_path,
                ], JSON_UNESCAPED_SLASHES));

                $success = 'Product added successfully. Barcode: ' . $barcode_value;
            } catch (Throwable $e) {
                if ($pdo->inTransaction()) {
                    $pdo->rollBack();
                }
                if ($photo_path) {
                    delete_product_photo_file($photo_path);
                }
                $errors[] = 'Failed to add product: ' . $e->getMessage();
            }
        }
    }

    if ($action === 'edit') {
        $id = post_int('id');
        $name = post_str('name');
        $sku = post_str('sku');
        $category_id = post_int('category_id') ?: null;
        $supplier_id = post_int('supplier_id') ?: null;
        $description = post_str('description');
        $unit = post_str('unit') ?: 'pcs';
        $cost_price = post_float('cost_price');
        $sell_price = post_float('sell_price');
        $reorder_level = max(0, post_int('reorder_level'));
        $is_active = post_int('is_active') ? 1 : 0;
        $barcode_value = normalize_barcode_value(post_str('barcode_value'));
        $remove_photo = post_int('remove_photo') === 1;

        $currentProduct = null;
        if ($id > 0) {
            $productStmt = $pdo->prepare('SELECT id, photo_path FROM products WHERE id = :id LIMIT 1');
            $productStmt->execute([':id' => $id]);
            $currentProduct = $productStmt->fetch(PDO::FETCH_ASSOC) ?: null;
        }

        if ($id <= 0 || !$currentProduct) {
            $errors[] = 'Invalid product ID.';
        }
        if ($name === '') {
            $errors[] = 'Product name is required.';
        }
        if ($sku === '') {
            $errors[] = 'SKU is required.';
        }
        if ($sku !== '' && product_exists_by_sku($pdo, $sku, $id)) {
            $errors[] = 'SKU already exists.';
        }
        if ($barcode_value === '') {
            $errors[] = 'Barcode is required.';
        } elseif (!is_supported_product_barcode($barcode_value)) {
            $errors[] = 'Barcode must be numeric and at least 12 digits.';
        } elseif (product_exists_by_barcode($pdo, $barcode_value, $id)) {
            $errors[] = 'Barcode already exists.';
        }

        $existingPhotoPath = (string)($currentProduct['photo_path'] ?? '');
        $finalPhotoPath = $existingPhotoPath;

        if ($remove_photo) {
            $finalPhotoPath = null;
        }

        $finalPhotoPath = handle_product_photo_upload('photo', $errors, $finalPhotoPath);

        if (!$errors) {
            try {
                $stmt = $pdo->prepare('
                    UPDATE products
                    SET
                        category_id = :category_id,
                        supplier_id = :supplier_id,
                        sku = :sku,
                        name = :name,
                        description = :description,
                        photo_path = :photo_path,
                        unit = :unit,
                        cost_price = :cost_price,
                        sell_price = :sell_price,
                        reorder_level = :reorder_level,
                        is_active = :is_active,
                        barcode_value = :barcode_value,
                        barcode_type = :barcode_type,
                        barcode_generated = 0
                    WHERE id = :id
                ');
                $stmt->execute([
                    ':category_id' => $category_id,
                    ':supplier_id' => $supplier_id,
                    ':sku' => $sku,
                    ':name' => $name,
                    ':description' => $description !== '' ? $description : null,
                    ':photo_path' => $finalPhotoPath ?: null,
                    ':unit' => $unit,
                    ':cost_price' => $cost_price,
                    ':sell_price' => $sell_price,
                    ':reorder_level' => $reorder_level,
                    ':is_active' => $is_active,
                    ':barcode_value' => $barcode_value,
                    ':barcode_type' => detect_barcode_type($barcode_value, false),
                    ':id' => $id,
                ]);

                if ($remove_photo && $existingPhotoPath !== '') {
                    delete_product_photo_file($existingPhotoPath);
                }

                audit_log('UPDATE_PRODUCT', 'products', (string)$id, json_encode([
                    'sku' => $sku,
                    'name' => $name,
                    'barcode_value' => $barcode_value,
                    'photo_path' => $finalPhotoPath,
                    'remove_photo' => $remove_photo,
                ], JSON_UNESCAPED_SLASHES));

                $success = 'Product updated successfully.';
            } catch (Throwable $e) {
                if ($finalPhotoPath && $finalPhotoPath !== $existingPhotoPath) {
                    delete_product_photo_file($finalPhotoPath);
                }
                $errors[] = 'Failed to update product: ' . $e->getMessage();
            }
        }
    }

    if ($action === 'delete') {
        $id = post_int('id');
        if ($id <= 0) {
            $errors[] = 'Invalid product ID.';
        }

        if (!$errors) {
            try {
                $pdo->beginTransaction();
                $productBeforeDelete = inventory_get_product($pdo, $id);

                $pdo->prepare('DELETE FROM inventory_movements WHERE product_id = :id')->execute([':id' => $id]);
                $pdo->prepare('DELETE FROM delivery_items WHERE product_id = :id')->execute([':id' => $id]);
                $pdo->prepare('DELETE FROM products WHERE id = :id')->execute([':id' => $id]);

                $pdo->commit();

                delete_product_photo_file($productBeforeDelete['photo_path'] ?? null);

                audit_log('DELETE_PRODUCT', 'products', (string)$id, json_encode([
                    'sku' => $productBeforeDelete['sku'] ?? null,
                    'name' => $productBeforeDelete['name'] ?? null,
                    'photo_path' => $productBeforeDelete['photo_path'] ?? null,
                ], JSON_UNESCAPED_SLASHES));

                $success = 'Product deleted successfully.';
            } catch (Throwable $e) {
                if ($pdo->inTransaction()) {
                    $pdo->rollBack();
                }
                $errors[] = 'Failed to delete product: ' . $e->getMessage();
            }
        }
    }
}

$categoriesMap = load_categories_map($pdo);
$categoryLabelCache = [];
$categories = sort_categories_for_dropdown($categoriesMap);

$suppliers = $pdo->query('SELECT id, name FROM suppliers WHERE is_active = 1 ORDER BY name ASC')->fetchAll(PDO::FETCH_ASSOC);

$params = [];
$where = '';
if ($q !== '') {
    $where = 'WHERE p.name LIKE :q OR p.sku LIKE :q OR p.barcode_value LIKE :q';
    $params[':q'] = '%' . $q . '%';
}

$sql = '
    SELECT
        p.*,
        c.name AS category_name,
        c.parent_id AS category_parent_id,
        s.name AS supplier_name,
        COALESCE(stock_summary.current_stock, p.quantity_on_hand, 0) AS current_stock
    FROM products p
    LEFT JOIN product_categories c ON c.id = p.category_id
    LEFT JOIN suppliers s ON s.id = p.supplier_id
    LEFT JOIN (
        SELECT m.product_id, ' . inventory_stock_expression('m') . ' AS current_stock
        FROM inventory_movements m
        GROUP BY m.product_id
    ) stock_summary ON stock_summary.product_id = p.id
    ' . $where . '
    ORDER BY p.id DESC
';

$hasCategoryParent = column_exists($pdo, 'product_categories', 'parent_id');
if (!$hasCategoryParent) {
    $sql = '
        SELECT
            p.*,
            c.name AS category_name,
            NULL AS category_parent_id,
            s.name AS supplier_name,
            COALESCE(stock_summary.current_stock, p.quantity_on_hand, 0) AS current_stock
        FROM products p
        LEFT JOIN product_categories c ON c.id = p.category_id
        LEFT JOIN suppliers s ON s.id = p.supplier_id
        LEFT JOIN (
            SELECT m.product_id, ' . inventory_stock_expression('m') . ' AS current_stock
            FROM inventory_movements m
            GROUP BY m.product_id
        ) stock_summary ON stock_summary.product_id = p.id
        ' . $where . '
        ORDER BY p.id DESC
    ';
}

$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$products = $stmt->fetchAll(PDO::FETCH_ASSOC);

$totalProducts = count($products);
$activeProducts = count(array_filter($products, static fn(array $row): bool => (int)$row['is_active'] === 1));
$lowStockProducts = count(array_filter($products, static function (array $row): bool {
    $stock = (int)$row['current_stock'];
    $reorder = (int)$row['reorder_level'];
    return $reorder > 0 && $stock <= $reorder;
}));
$generatedBarcodes = count(array_filter($products, static fn(array $row): bool => (int)$row['barcode_generated'] === 1));

require_once __DIR__ . '/../templates/header.php';
require_once __DIR__ . '/../templates/sidebar.php';
?>
<style>
  .product-photo-thumb,
  .product-photo-thumb-placeholder {
    width: 56px;
    height: 56px;
    border-radius: 14px;
    object-fit: cover;
    flex: 0 0 56px;
    border: 1px solid rgba(15, 23, 42, 0.08);
    background: #f8fafc;
  }
  .product-photo-thumb-placeholder {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    color: #64748b;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
  }
  .product-photo-preview-box {
    width: 132px;
    height: 132px;
    border-radius: 18px;
    border: 1px dashed rgba(15, 23, 42, 0.18);
    background: #f8fafc;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .product-photo-preview-box img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
  .product-photo-preview-empty {
    font-size: 12px;
    color: #64748b;
    text-align: center;
    padding: 12px;
  }
  .product-view-photo,
  .product-view-photo-placeholder {
    width: 100%;
    max-width: 280px;
    aspect-ratio: 1 / 1;
    border-radius: 22px;
    object-fit: cover;
    border: 1px solid rgba(15, 23, 42, 0.08);
    background: #f8fafc;
  }
  .product-view-photo-placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    color: #64748b;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
  }
  .product-view-meta {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 12px;
  }
  .product-view-meta-card {
    border: 1px solid rgba(15, 23, 42, 0.08);
    border-radius: 16px;
    padding: 12px 14px;
    background: #fff;
  }
  .product-view-meta-label {
    color: #64748b;
    font-size: 12px;
    margin-bottom: 4px;
    text-transform: uppercase;
    letter-spacing: .04em;
  }
  #scannerViewport {
    width: 100%;
    min-height: 320px;
    border-radius: 18px;
    overflow: hidden;
    background: #020617;
    position: relative;
  }
  #scannerViewport video {
    width: 100%;
    height: 320px;
    object-fit: cover;
    display: block;
  }
  .scanner-frame {
    position: absolute;
    inset: 50% auto auto 50%;
    width: min(78%, 340px);
    height: 120px;
    transform: translate(-50%, -50%);
    border: 2px solid rgba(255,255,255,.9);
    border-radius: 18px;
    box-shadow: 0 0 0 9999px rgba(2, 6, 23, 0.35);
    pointer-events: none;
  }
</style>

<main class="col-12 col-lg-10 app-content">
  <div class="page-head">
    <div>
      <div class="page-kicker">Catalog</div>
      <h1 class="page-title">Products</h1>
      <p class="page-subtitle">Manage your product master data, barcode assignments, pricing, reorder thresholds, category hierarchy safely.</p>
    </div>
    <form class="d-flex gap-2 align-items-start flex-wrap justify-content-end" method="get">
      <input class="form-control" name="q" placeholder="Search name, SKU, or barcode" value="<?= h($q) ?>">
      <button class="btn btn-outline-secondary" type="submit">Search</button>
      <button class="btn btn-outline-dark" type="button" id="openScannerBtn">Scan barcode</button>
      <?php if ($q !== ''): ?>
        <a class="btn btn-outline-secondary" href="products.php">Reset</a>
      <?php endif; ?>
    </form>
  </div>

  <div class="row g-3 mb-3">
    <div class="col-12 col-sm-6 col-xl-3"><div class="stat-card"><div class="stat-label">Visible products</div><div class="stat-value"><?= $totalProducts ?></div><div class="stat-sub">Current result set</div></div></div>
    <div class="col-12 col-sm-6 col-xl-3"><div class="stat-card"><div class="stat-label">Active</div><div class="stat-value"><?= $activeProducts ?></div><div class="stat-sub">Ready for inventory transactions</div></div></div>
    <div class="col-12 col-sm-6 col-xl-3"><div class="stat-card"><div class="stat-label">Low stock</div><div class="stat-value"><?= $lowStockProducts ?></div><div class="stat-sub">At or below reorder level</div></div></div>
    <div class="col-12 col-sm-6 col-xl-3"><div class="stat-card"><div class="stat-label">Auto barcodes</div><div class="stat-value"><?= $generatedBarcodes ?></div><div class="stat-sub">Generated internally</div></div></div>
  </div>

  <?php if ($errors): ?>
    <div class="alert alert-danger mb-3">
      <ul class="mb-0 ps-3">
        <?php foreach ($errors as $error): ?>
          <li><?= h($error) ?></li>
        <?php endforeach; ?>
      </ul>
    </div>
  <?php endif; ?>

  <?php if ($success !== ''): ?>
    <div class="alert alert-success mb-3"><?= h($success) ?></div>
  <?php endif; ?>

  <div class="row g-3 align-items-start">
    <div class="col-12 col-xl-4">
      <div class="card">
        <div class="card-body p-4">
          <div class="d-flex justify-content-between align-items-center mb-3">
            <div>
              <h5 class="mb-1">Add product</h5>
              <div class="text-muted small">Leave barcode blank to auto-generate an internal 12-digit barcode, or enter the product's real barcode (12 digits or more).</div>
            </div>
          </div>

          <form method="post" enctype="multipart/form-data" autocomplete="off" class="d-grid gap-3">
            <input type="hidden" name="action" value="add">
            <div>
              <label class="form-label">Product name</label>
              <input class="form-control" type="text" name="name" required>
            </div>
            <div class="row g-3">
              <div class="col-md-6">
                <label class="form-label">SKU</label>
                <input class="form-control" type="text" name="sku" required>
              </div>
              <div class="col-md-6">
                <label class="form-label">Unit</label>
                <input class="form-control" type="text" name="unit" value="pcs">
              </div>
            </div>
            <div class="row g-3">
              <div class="col-md-6">
                <label class="form-label">Category</label>
                <select class="form-select" name="category_id">
                  <option value="0">No category</option>
                  <?php foreach ($categories as $category): ?>
                    <?php
                      $catId = (int)$category['id'];
                      $catLabel = build_category_label($catId, $categoriesMap, $categoryLabelCache);
                    ?>
                    <option value="<?= $catId ?>"><?= h($catLabel) ?></option>
                  <?php endforeach; ?>
                </select>
              </div>
              <div class="col-md-6">
                <label class="form-label">Supplier</label>
                <select class="form-select" name="supplier_id">
                  <option value="0">No supplier</option>
                  <?php foreach ($suppliers as $supplier): ?>
                    <option value="<?= (int)$supplier['id'] ?>"><?= h($supplier['name']) ?></option>
                  <?php endforeach; ?>
                </select>
              </div>
            </div>
            <div class="row g-3">
              <div class="col-md-6">
                <label class="form-label">Cost price</label>
                <input class="form-control" type="number" step="0.01" min="0" name="cost_price" value="0">
              </div>
              <div class="col-md-6">
                <label class="form-label">Sell price</label>
                <input class="form-control" type="number" step="0.01" min="0" name="sell_price" value="0">
              </div>
            </div>
            <div class="row g-3">
              <div class="col-md-6">
                <label class="form-label">Reorder level</label>
                <input class="form-control" type="number" min="0" name="reorder_level" value="0">
              </div>
              <div class="col-md-6">
                <label class="form-label">Active</label>
                <select class="form-select" name="is_active">
                  <option value="1" selected>Yes</option>
                  <option value="0">No</option>
                </select>
              </div>
            </div>
            <div>
              <label class="form-label">Product photo</label>
              <input class="form-control" type="file" name="photo" accept="image/jpeg,image/png,image/webp,image/gif">
              <div class="form-text">Optional. JPG, PNG, WEBP, or GIF. Maximum 5MB.</div>
            </div>
            <div>
              <label class="form-label">Barcode</label>
              <input class="form-control" type="text" inputmode="numeric" pattern="[0-9]*" name="barcode_value" maxlength="32" placeholder="Leave blank to auto-generate or enter 12+ digits">
            </div>
            <div>
              <label class="form-label">Description</label>
              <textarea class="form-control" name="description" rows="3"></textarea>
            </div>
            <button class="btn btn-dark w-100" type="submit">Save product</button>
          </form>
        </div>
      </div>
    </div>

    <div class="col-12 col-xl-8">
      <div class="card">
        <div class="card-body p-4">
          <div class="d-flex justify-content-between align-items-center mb-3">
            <div>
              <h5 class="mb-1">Product list</h5>
              <div class="text-muted small">Live stock is computed from inventory movements so the list stays accurate even if historical data was imported.</div>
            </div>
          </div>

          <div class="table-responsive">
            <table class="table align-middle">
              <thead>
                <tr>
                  <th>Photo</th>
                  <th>Product</th>
                  <th>Barcode</th>
                  <th>Price</th>
                  <th class="text-end">Stock</th>
                  <th>Status</th>
                  <th class="text-end">Actions</th>
                </tr>
              </thead>
              <tbody>
                <?php if (!$products): ?>
                  <tr>
                    <td colspan="7" class="text-muted">No products found.</td>
                  </tr>
                <?php else: ?>
                  <?php foreach ($products as $product): ?>
                    <?php
                    $currentStock = (int)$product['current_stock'];
                    $reorderLevel = (int)$product['reorder_level'];
                    $stockState = ($reorderLevel > 0 && $currentStock <= $reorderLevel) ? 'LOW' : 'OK';
                    $categoryId = (int)($product['category_id'] ?? 0);
                    $categoryLabel = $categoryId > 0
                        ? build_category_label($categoryId, $categoriesMap, $categoryLabelCache)
                        : '';
                    $photoUrl = product_photo_url($product['photo_path'] ?? null);
                    ?>
                    <tr>
                      <td>
                        <?php if ($photoUrl !== ''): ?>
                          <img src="<?= h($photoUrl) ?>" alt="<?= h($product['name']) ?>" class="product-photo-thumb">
                        <?php else: ?>
                          <span class="product-photo-thumb-placeholder">No photo</span>
                        <?php endif; ?>
                      </td>
                      <td>
                        <div class="fw-semibold"><?= h($product['name']) ?></div>
                        <div class="small text-muted">
                          <span class="code-chip"><?= h($product['sku']) ?></span>
                          <?php if ($categoryLabel !== ''): ?>
                            · <?= h($categoryLabel) ?>
                          <?php endif; ?>
                          <?php if (!empty($product['supplier_name'])): ?>
                            · <?= h($product['supplier_name']) ?>
                          <?php endif; ?>
                        </div>
                      </td>
                      <td>
                        <div class="code-chip"><?= h($product['barcode_value']) ?></div>
                        <div class="small text-muted mt-1"><?= ((int)$product['barcode_generated'] === 1) ? 'Auto-generated' : 'Manual barcode' ?></div>
                      </td>
                      <td>
                        <div class="fw-semibold"><?= format_money((float)$product['sell_price']) ?></div>
                        <div class="small text-muted">Cost <?= format_money((float)$product['cost_price']) ?></div>
                      </td>
                      <td class="text-end">
                        <div class="fw-semibold"><?= $currentStock ?></div>
                        <div class="small text-muted">Reorder <?= $reorderLevel ?></div>
                      </td>
                      <td>
                        <div class="<?= status_pill_class($stockState) ?> mb-1"><?= $stockState === 'LOW' ? 'Low stock' : 'Healthy' ?></div>
                        <div class="small text-muted"><?= ((int)$product['is_active'] === 1) ? 'Active' : 'Inactive' ?></div>
                      </td>
                      <td class="text-end">
                        <div class="d-inline-flex gap-1 flex-wrap justify-content-end">
                          <button
                            type="button"
                            class="btn btn-sm btn-outline-dark"
                            onclick='openView(<?= json_encode([
                                'id' => (int)$product['id'],
                                'name' => (string)$product['name'],
                                'sku' => (string)$product['sku'],
                                'category' => $categoryLabel,
                                'supplier' => (string)($product['supplier_name'] ?? ''),
                                'description' => (string)($product['description'] ?? ''),
                                'unit' => (string)($product['unit'] ?? 'pcs'),
                                'cost_price' => (float)$product['cost_price'],
                                'sell_price' => (float)$product['sell_price'],
                                'reorder_level' => $reorderLevel,
                                'current_stock' => $currentStock,
                                'barcode_value' => (string)($product['barcode_value'] ?? ''),
                                'barcode_generated' => (int)$product['barcode_generated'],
                                'barcode_type' => (string)($product['barcode_type'] ?? ''),
                                'is_active' => (int)$product['is_active'],
                                'stock_state' => $stockState,
                                'photo_path' => (string)($product['photo_path'] ?? ''),
                                'photo_url' => $photoUrl,
                            ], JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>)'
                          >View</button>
                          <button
                            type="button"
                            class="btn btn-sm btn-outline-primary"
                            onclick='openEdit(<?= json_encode([
                                'id' => (int)$product['id'],
                                'name' => (string)$product['name'],
                                'sku' => (string)$product['sku'],
                                'category_id' => (int)($product['category_id'] ?? 0),
                                'supplier_id' => (int)($product['supplier_id'] ?? 0),
                                'description' => (string)($product['description'] ?? ''),
                                'unit' => (string)($product['unit'] ?? 'pcs'),
                                'cost_price' => (string)$product['cost_price'],
                                'sell_price' => (string)$product['sell_price'],
                                'reorder_level' => (int)$product['reorder_level'],
                                'barcode_value' => (string)($product['barcode_value'] ?? ''),
                                'is_active' => (int)$product['is_active'],
                                'photo_path' => (string)($product['photo_path'] ?? ''),
                                'photo_url' => $photoUrl,
                            ], JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>)'
                          >Edit</button>
                          <a class="btn btn-sm btn-outline-secondary" target="_blank" href="print_label.php?id=<?= (int)$product['id'] ?>&mode=both">Print</a>
                          <form method="post" class="d-inline" onsubmit="return confirm('Delete this product? This also removes related delivery items and stock history for this product.');">
                            <input type="hidden" name="action" value="delete">
                            <input type="hidden" name="id" value="<?= (int)$product['id'] ?>">
                            <button class="btn btn-sm btn-outline-danger" type="submit">Delete</button>
                          </form>
                        </div>
                      </td>
                    </tr>
                  <?php endforeach; ?>
                <?php endif; ?>
              </tbody>
            </table>
          </div>
        </div>
      </div>
    </div>
  </div>
</main>

<div class="modal fade" id="viewModal" tabindex="-1" aria-hidden="true">
  <div class="modal-dialog modal-xl modal-dialog-centered modal-dialog-scrollable">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">Product details</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        <div class="row g-4 align-items-start">
          <div class="col-12 col-lg-4">
            <div id="view_photo_wrap" class="d-flex justify-content-center"></div>
          </div>
          <div class="col-12 col-lg-8">
            <div class="d-flex flex-wrap justify-content-between gap-3 align-items-start mb-3">
              <div>
                <h3 class="mb-1" id="view_name">-</h3>
                <div class="text-muted" id="view_description">No description</div>
              </div>
              <div class="text-lg-end">
                <div class="small text-muted">Barcode</div>
                <div class="code-chip" id="view_barcode_value">-</div>
              </div>
            </div>
            <div class="product-view-meta">
              <div class="product-view-meta-card"><div class="product-view-meta-label">SKU</div><div class="fw-semibold" id="view_sku">-</div></div>
              <div class="product-view-meta-card"><div class="product-view-meta-label">Category</div><div class="fw-semibold" id="view_category">-</div></div>
              <div class="product-view-meta-card"><div class="product-view-meta-label">Supplier</div><div class="fw-semibold" id="view_supplier">-</div></div>
              <div class="product-view-meta-card"><div class="product-view-meta-label">Unit</div><div class="fw-semibold" id="view_unit">-</div></div>
              <div class="product-view-meta-card"><div class="product-view-meta-label">Sell price</div><div class="fw-semibold" id="view_sell_price">-</div></div>
              <div class="product-view-meta-card"><div class="product-view-meta-label">Cost price</div><div class="fw-semibold" id="view_cost_price">-</div></div>
              <div class="product-view-meta-card"><div class="product-view-meta-label">Current stock</div><div class="fw-semibold" id="view_current_stock">-</div></div>
              <div class="product-view-meta-card"><div class="product-view-meta-label">Reorder level</div><div class="fw-semibold" id="view_reorder_level">-</div></div>
              <div class="product-view-meta-card"><div class="product-view-meta-label">Status</div><div class="fw-semibold" id="view_status">-</div></div>
              <div class="product-view-meta-card"><div class="product-view-meta-label">Barcode type</div><div class="fw-semibold" id="view_barcode_type">-</div></div>
            </div>
          </div>
        </div>
      </div>
      <div class="modal-footer">
        <button class="btn btn-outline-secondary" type="button" data-bs-dismiss="modal">Close</button>
      </div>
    </div>
  </div>
</div>

<div class="modal fade" id="scannerModal" tabindex="-1" aria-hidden="true">
  <div class="modal-dialog modal-lg modal-dialog-centered">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">Scan product barcode</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        <div id="scannerViewport">
          <video id="scannerVideo" playsinline muted></video>
          <div class="scanner-frame"></div>
        </div>
        <div class="small text-muted mt-2">Point the camera at the barcode. When detected, the product information will open automatically.</div>
        <div class="alert alert-danger mt-3 d-none" id="scannerError"></div>
        <div class="mt-3">
          <label class="form-label">Or enter barcode manually</label>
          <div class="d-flex gap-2">
            <input type="text" class="form-control" id="scannerManualBarcode" inputmode="numeric" placeholder="Enter barcode">
            <button type="button" class="btn btn-outline-secondary" id="scannerManualLookupBtn">Find</button>
          </div>
        </div>
      </div>
      <div class="modal-footer">
        <button class="btn btn-outline-secondary" type="button" data-bs-dismiss="modal">Close</button>
      </div>
    </div>
  </div>
</div>

<div class="modal fade" id="editModal" tabindex="-1" aria-hidden="true">
  <div class="modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable">
    <div class="modal-content">
      <form method="post" enctype="multipart/form-data" autocomplete="off">
        <div class="modal-header">
          <h5 class="modal-title">Edit product</h5>
          <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
        </div>
        <div class="modal-body">
          <input type="hidden" name="action" value="edit">
          <input type="hidden" name="id" id="edit_id">
          <div class="row g-3">
            <div class="col-12">
              <label class="form-label">Product name</label>
              <input class="form-control" type="text" name="name" id="edit_name" required>
            </div>
            <div class="col-md-6">
              <label class="form-label">SKU</label>
              <input class="form-control" type="text" name="sku" id="edit_sku" required>
            </div>
            <div class="col-md-6">
              <label class="form-label">Unit</label>
              <input class="form-control" type="text" name="unit" id="edit_unit">
            </div>
            <div class="col-md-6">
              <label class="form-label">Category</label>
              <select class="form-select" name="category_id" id="edit_category_id">
                <option value="0">No category</option>
                <?php foreach ($categories as $category): ?>
                  <?php
                    $catId = (int)$category['id'];
                    $catLabel = build_category_label($catId, $categoriesMap, $categoryLabelCache);
                  ?>
                  <option value="<?= $catId ?>"><?= h($catLabel) ?></option>
                <?php endforeach; ?>
              </select>
            </div>
            <div class="col-md-6">
              <label class="form-label">Supplier</label>
              <select class="form-select" name="supplier_id" id="edit_supplier_id">
                <option value="0">No supplier</option>
                <?php foreach ($suppliers as $supplier): ?>
                  <option value="<?= (int)$supplier['id'] ?>"><?= h($supplier['name']) ?></option>
                <?php endforeach; ?>
              </select>
            </div>
            <div class="col-md-6">
              <label class="form-label">Cost price</label>
              <input class="form-control" type="number" step="0.01" min="0" name="cost_price" id="edit_cost_price">
            </div>
            <div class="col-md-6">
              <label class="form-label">Sell price</label>
              <input class="form-control" type="number" step="0.01" min="0" name="sell_price" id="edit_sell_price">
            </div>
            <div class="col-md-6">
              <label class="form-label">Reorder level</label>
              <input class="form-control" type="number" min="0" name="reorder_level" id="edit_reorder_level">
            </div>
            <div class="col-md-6">
              <label class="form-label">Active</label>
              <select class="form-select" name="is_active" id="edit_is_active">
                <option value="1">Yes</option>
                <option value="0">No</option>
              </select>
            </div>
            <div class="col-12">
              <label class="form-label">Current photo</label>
              <div class="product-photo-preview-box" id="edit_photo_preview">
                <div class="product-photo-preview-empty">No photo uploaded</div>
              </div>
            </div>
            <div class="col-md-8">
              <label class="form-label">Change photo</label>
              <input class="form-control" type="file" name="photo" id="edit_photo_input" accept="image/jpeg,image/png,image/webp,image/gif">
              <div class="form-text">Optional. Upload a new file only if you want to replace the current product photo.</div>
            </div>
            <div class="col-md-4 d-flex align-items-end">
              <div class="form-check mb-2">
                <input class="form-check-input" type="checkbox" name="remove_photo" id="edit_remove_photo" value="1">
                <label class="form-check-label" for="edit_remove_photo">Remove current photo</label>
              </div>
            </div>
            <div class="col-12">
              <label class="form-label">Barcode</label>
              <input class="form-control" type="text" inputmode="numeric" pattern="[0-9]*" maxlength="32" name="barcode_value" id="edit_barcode_value" required>
            </div>
            <div class="col-12">
              <label class="form-label">Description</label>
              <textarea class="form-control" name="description" id="edit_description" rows="3"></textarea>
            </div>
          </div>
        </div>
        <div class="modal-footer">
          <button class="btn btn-outline-secondary" type="button" data-bs-dismiss="modal">Cancel</button>
          <button class="btn btn-dark" type="submit">Save changes</button>
        </div>
      </form>
    </div>
  </div>
</div>

<?php require_once __DIR__ . '/../templates/footer.php'; ?>
<script>
  const editModal = new bootstrap.Modal(document.getElementById('editModal'));
  const viewModal = new bootstrap.Modal(document.getElementById('viewModal'));
  const scannerModalEl = document.getElementById('scannerModal');
  const scannerModal = new bootstrap.Modal(scannerModalEl);
  const scannerVideo = document.getElementById('scannerVideo');
  const scannerError = document.getElementById('scannerError');
  let scannerStream = null;
  let scannerAnimationFrame = null;
  let scannerActive = false;
  let scannerDetector = null;
  let scannerLastCode = '';
  let scannerLastCodeAt = 0;

  function formatMoney(amount) {
    const numeric = Number(amount || 0);
    return '€' + numeric.toFixed(2);
  }

  function renderEditPhotoPreview(url) {
    const box = document.getElementById('edit_photo_preview');
    if (!box) return;

    if (url) {
      box.innerHTML = '<img src="' + url.replace(/"/g, '&quot;') + '" alt="Product photo preview">';
    } else {
      box.innerHTML = '<div class="product-photo-preview-empty">No photo uploaded</div>';
    }
  }

  function renderViewPhoto(url, name) {
    const wrap = document.getElementById('view_photo_wrap');
    if (!wrap) return;

    if (url) {
      wrap.innerHTML = '<img class="product-view-photo" src="' + url.replace(/"/g, '&quot;') + '" alt="' + String(name || 'Product photo').replace(/"/g, '&quot;') + '">';
    } else {
      wrap.innerHTML = '<div class="product-view-photo-placeholder">No photo</div>';
    }
  }

  function openView(payload) {
    renderViewPhoto(payload.photo_url || '', payload.name || '');
    document.getElementById('view_name').textContent = payload.name || '-';
    document.getElementById('view_description').textContent = payload.description || 'No description';
    document.getElementById('view_barcode_value').textContent = payload.barcode_value || '-';
    document.getElementById('view_sku').textContent = payload.sku || '-';
    document.getElementById('view_category').textContent = payload.category || '-';
    document.getElementById('view_supplier').textContent = payload.supplier || '-';
    document.getElementById('view_unit').textContent = payload.unit || '-';
    document.getElementById('view_sell_price').textContent = formatMoney(payload.sell_price || 0);
    document.getElementById('view_cost_price').textContent = formatMoney(payload.cost_price || 0);
    document.getElementById('view_current_stock').textContent = String(payload.current_stock ?? '-');
    document.getElementById('view_reorder_level').textContent = String(payload.reorder_level ?? '-');
    document.getElementById('view_status').textContent = (payload.stock_state === 'LOW' ? 'Low stock' : 'Healthy') + ((payload.is_active === 1 || payload.is_active === '1') ? ' · Active' : ' · Inactive');
    document.getElementById('view_barcode_type').textContent = payload.barcode_generated === 1 || payload.barcode_generated === '1'
      ? 'Auto-generated ' + (payload.barcode_type || '')
      : (payload.barcode_type || 'Manual');
    viewModal.show();
  }

  function openEdit(payload) {
    document.getElementById('edit_id').value = payload.id || '';
    document.getElementById('edit_name').value = payload.name || '';
    document.getElementById('edit_sku').value = payload.sku || '';
    document.getElementById('edit_category_id').value = payload.category_id || 0;
    document.getElementById('edit_supplier_id').value = payload.supplier_id || 0;
    document.getElementById('edit_description').value = payload.description || '';
    document.getElementById('edit_unit').value = payload.unit || 'pcs';
    document.getElementById('edit_cost_price').value = payload.cost_price || 0;
    document.getElementById('edit_sell_price').value = payload.sell_price || 0;
    document.getElementById('edit_reorder_level').value = payload.reorder_level || 0;
    document.getElementById('edit_barcode_value').value = payload.barcode_value || '';
    document.getElementById('edit_is_active').value = (payload.is_active === 1 || payload.is_active === '1') ? '1' : '0';
    document.getElementById('edit_remove_photo').checked = false;
    document.getElementById('edit_photo_input').value = '';
    renderEditPhotoPreview(payload.photo_url || '');
    editModal.show();
  }

  async function lookupBarcodeAndOpen(barcode) {
    const clean = String(barcode || '').replace(/\\D+/g, '');
    if (!clean) {
      throw new Error('Barcode is required.');
    }

    const response = await fetch('products.php?ajax=lookup_barcode&barcode=' + encodeURIComponent(clean), {
      headers: { 'Accept': 'application/json' }
    });

    const data = await response.json().catch(() => ({ ok: false, message: 'Invalid server response.' }));
    if (!response.ok || !data.ok || !data.product) {
      throw new Error(data.message || 'Product not found.');
    }

    scannerModal.hide();
    openView(data.product);
    return data.product;
  }

  function setScannerError(message) {
    if (!scannerError) return;
    if (message) {
      scannerError.textContent = message;
      scannerError.classList.remove('d-none');
    } else {
      scannerError.textContent = '';
      scannerError.classList.add('d-none');
    }
  }

  async function scanLoop() {
    if (!scannerActive || !scannerDetector || !scannerVideo) return;

    try {
      if (scannerVideo.readyState >= 2) {
        const barcodes = await scannerDetector.detect(scannerVideo);
        if (Array.isArray(barcodes) && barcodes.length > 0) {
          const raw = String(barcodes[0].rawValue || '').trim();
          if (raw) {
            const now = Date.now();
            if (raw !== scannerLastCode || (now - scannerLastCodeAt) > 1500) {
              scannerLastCode = raw;
              scannerLastCodeAt = now;
              try {
                await lookupBarcodeAndOpen(raw);
                return;
              } catch (error) {
                setScannerError(error.message || 'No product found for this barcode.');
              }
            }
          }
        }
      }
    } catch (error) {
      setScannerError(error.message || 'Unable to scan barcode.');
    }

    if (scannerActive) {
      scannerAnimationFrame = requestAnimationFrame(scanLoop);
    }
  }

  async function startScanner() {
    setScannerError('');
    scannerLastCode = '';
    scannerLastCodeAt = 0;

    if (!('mediaDevices' in navigator) || !navigator.mediaDevices.getUserMedia) {
      setScannerError('Camera access is not supported in this browser.');
      return;
    }

    if (!('BarcodeDetector' in window)) {
      setScannerError('Barcode scanning is not supported in this browser. Use Chrome on HTTPS or enter the barcode manually.');
      return;
    }

    try {
      scannerDetector = new BarcodeDetector({
        formats: ['ean_13', 'ean_8', 'upc_a', 'upc_e', 'code_128', 'code_39', 'itf', 'codabar']
      });
    } catch (error) {
      setScannerError('This device does not support barcode detection.');
      return;
    }

    try {
      scannerStream = await navigator.mediaDevices.getUserMedia({
        video: {
          facingMode: { ideal: 'environment' },
          width: { ideal: 1280 },
          height: { ideal: 720 }
        },
        audio: false
      });

      scannerVideo.srcObject = scannerStream;
      await scannerVideo.play();
      scannerActive = true;
      scanLoop();
    } catch (error) {
      setScannerError('Unable to access camera. Please allow camera permission.');
    }
  }

  function stopScanner() {
    scannerActive = false;
    if (scannerAnimationFrame) {
      cancelAnimationFrame(scannerAnimationFrame);
      scannerAnimationFrame = null;
    }
    if (scannerVideo) {
      scannerVideo.pause();
      scannerVideo.srcObject = null;
    }
    if (scannerStream) {
      scannerStream.getTracks().forEach(track => track.stop());
      scannerStream = null;
    }
  }

  document.getElementById('openScannerBtn')?.addEventListener('click', function () {
    scannerModal.show();
  });

  scannerModalEl?.addEventListener('shown.bs.modal', function () {
    startScanner();
  });

  scannerModalEl?.addEventListener('hidden.bs.modal', function () {
    stopScanner();
    setScannerError('');
    const manualInput = document.getElementById('scannerManualBarcode');
    if (manualInput) {
      manualInput.value = '';
    }
  });

  document.getElementById('scannerManualLookupBtn')?.addEventListener('click', async function () {
    const manualValue = document.getElementById('scannerManualBarcode')?.value || '';
    setScannerError('');
    try {
      await lookupBarcodeAndOpen(manualValue);
    } catch (error) {
      setScannerError(error.message || 'Product not found.');
    }
  });

  document.getElementById('scannerManualBarcode')?.addEventListener('keydown', function (event) {
    if (event.key === 'Enter') {
      event.preventDefault();
      document.getElementById('scannerManualLookupBtn')?.click();
    }
  });

  document.getElementById('edit_remove_photo')?.addEventListener('change', function () {
    if (this.checked) {
      renderEditPhotoPreview('');
    }
  });

  document.getElementById('edit_photo_input')?.addEventListener('change', function () {
    const file = this.files && this.files[0] ? this.files[0] : null;
    if (!file) return;

    document.getElementById('edit_remove_photo').checked = false;

    const reader = new FileReader();
    reader.onload = function (e) {
      renderEditPhotoPreview((e.target && e.target.result) ? String(e.target.result) : '');
    };
    reader.readAsDataURL(file);
  });
</script>
