<?php
declare(strict_types=1);

require_once __DIR__ . '/../app/bootstrap.php';

use App\Core\Auth;
use App\Core\Database;
use App\Core\Security;

Auth::requireRole(['admin', 'staff']);
$pageTitle = 'Products | Admin';
$errors = [];

/**
 * Produce a valid EAN-13 barcode that is unique in the products table.
 */
function admin_product_barcode(?int $ignoreId = null): string
{
    for ($attempt = 0; $attempt < 20; $attempt++) {
        $base = '2' . str_pad((string) random_int(0, 99999999999), 11, '0', STR_PAD_LEFT);
        $sum = 0;
        for ($i = 0; $i < 12; $i++) {
            $sum += ((int) $base[$i]) * (($i % 2 === 0) ? 1 : 3);
        }
        $barcode = $base . ((10 - ($sum % 10)) % 10);
        $sql = 'SELECT id FROM products WHERE barcode=?' . ($ignoreId ? ' AND id<>?' : '') . ' LIMIT 1';
        $params = $ignoreId ? [$barcode, $ignoreId] : [$barcode];
        if (!Database::safeFetchOne($sql, $params)) {
            return $barcode;
        }
    }
    return (string) (time() . random_int(1000, 9999));
}

function admin_product_code(?int $ignoreId = null): string
{
    for ($attempt = 0; $attempt < 20; $attempt++) {
        $code = 'PRD-' . date('ymd') . '-' . strtoupper(bin2hex(random_bytes(3)));
        $sql = 'SELECT id FROM products WHERE product_code=?' . ($ignoreId ? ' AND id<>?' : '') . ' LIMIT 1';
        $params = $ignoreId ? [$code, $ignoreId] : [$code];
        if (!Database::safeFetchOne($sql, $params)) {
            return $code;
        }
    }
    return 'PRD-' . date('ymdHis') . '-' . random_int(100, 999);
}

/**
 * Validate and store one product image. Returns a path compatible with product_image().
 */
function admin_store_product_image(array $file, string $type = 'gallery'): ?string
{
    $error = (int) ($file['error'] ?? UPLOAD_ERR_NO_FILE);
    if ($error === UPLOAD_ERR_NO_FILE) {
        return null;
    }
    if ($error !== UPLOAD_ERR_OK || !is_uploaded_file((string) ($file['tmp_name'] ?? ''))) {
        throw new RuntimeException('One of the selected images could not be uploaded.');
    }

    $size = (int) ($file['size'] ?? 0);
    if ($size < 1 || $size > MAX_UPLOAD_BYTES) {
        throw new RuntimeException('Each image must be smaller than ' . number_format(MAX_UPLOAD_BYTES / 1048576, 1) . ' MB.');
    }

    $tmp = (string) $file['tmp_name'];
    $mime = (new finfo(FILEINFO_MIME_TYPE))->file($tmp) ?: '';
    $extensions = ['image/jpeg' => 'jpg', 'image/png' => 'png', 'image/webp' => 'webp'];
    if (!isset($extensions[$mime])) {
        throw new RuntimeException('Only JPG, PNG and WEBP product images are allowed.');
    }

    $info = @getimagesize($tmp);
    if (!$info || ($info['mime'] ?? '') !== $mime) {
        throw new RuntimeException('An uploaded image is invalid.');
    }
    $pixels = (int) $info[0] * (int) $info[1];
    if ($pixels < 1 || $pixels > MAX_IMAGE_PIXELS) {
        throw new RuntimeException('An uploaded image has dimensions that are too large.');
    }

    $relativeDirectory = 'public/uploads/products/' . date('Y/m');
    $directory = ROOT_PATH . '/' . $relativeDirectory;
    if (!is_dir($directory) && !mkdir($directory, 0755, true) && !is_dir($directory)) {
        throw new RuntimeException('The product upload directory is not writable.');
    }

    $filename = $type . '-' . bin2hex(random_bytes(16)) . '.' . $extensions[$mime];
    $absolutePath = $directory . '/' . $filename;
    if (!move_uploaded_file($tmp, $absolutePath)) {
        throw new RuntimeException('The uploaded image could not be saved.');
    }
    @chmod($absolutePath, 0644);

    $relativePath = $relativeDirectory . '/' . $filename;
    Database::safeExecute(
        'INSERT INTO media_files (disk,file_name,file_path,mime_type,file_size,uploaded_by,created_at) VALUES ("public",?,?,?,?,?,NOW())',
        [basename((string) ($file['name'] ?? $filename)), $relativePath, $mime, $size, Auth::id()]
    );
    return $relativePath;
}

function admin_normalize_multi_upload(array $files): array
{
    $normalized = [];
    $names = $files['name'] ?? [];
    if (!is_array($names)) {
        return [];
    }
    foreach ($names as $index => $name) {
        $normalized[] = [
            'name' => $name,
            'type' => $files['type'][$index] ?? '',
            'tmp_name' => $files['tmp_name'][$index] ?? '',
            'error' => $files['error'][$index] ?? UPLOAD_ERR_NO_FILE,
            'size' => $files['size'][$index] ?? 0,
        ];
    }
    return $normalized;
}

function admin_product_keywords(string $name, string $categoryName = '', string $brandName = ''): string
{
    $parts = [$name, $categoryName, $brandName];
    $words = [];
    foreach ($parts as $part) {
        foreach (preg_split('/[^\pL\pN]+/u', mb_strtolower($part)) ?: [] as $word) {
            $word = trim($word);
            if ($word !== '' && mb_strlen($word) > 1) {
                $words[$word] = true;
            }
        }
    }
    foreach (['buy online', 'best price', 'bangladesh', 'smart tech omp'] as $phrase) {
        $words[$phrase] = true;
    }
    return implode(', ', array_slice(array_keys($words), 0, 20));
}

function admin_local_upload_path(string $path): ?string
{
    $path = ltrim($path, '/');
    if (!str_starts_with($path, 'public/uploads/products/')) {
        return null;
    }
    $absolute = ROOT_PATH . '/' . $path;
    $root = realpath(ROOT_PATH . '/public/uploads/products');
    $parent = realpath(dirname($absolute));
    if ($root && $parent && str_starts_with($parent, $root) && is_file($absolute)) {
        return $absolute;
    }
    return null;
}

$vendors = Database::safeFetchAll(
    'SELECT v.id,v.shop_name,v.status,u.name owner_name FROM vendors v LEFT JOIN users u ON u.id=v.user_id WHERE v.status IN ("approved","active") ORDER BY v.shop_name'
);
$categories = Database::safeFetchAll('SELECT id,parent_id,name,status,sort_order FROM categories WHERE status="active" ORDER BY parent_id,sort_order,name');
$brands = Database::safeFetchAll('SELECT id,name,status FROM brands WHERE status="active" ORDER BY name');

$categoryNames = [];
foreach ($categories as $category) {
    $categoryNames[(int) $category['id']] = (string) $category['name'];
}
$brandNames = [];
foreach ($brands as $brand) {
    $brandNames[(int) $brand['id']] = (string) $brand['name'];
}

$editingId = max(0, (int) ($_GET['edit'] ?? $_POST['id'] ?? 0));
$editing = $editingId > 0 ? Database::safeFetchOne('SELECT * FROM products WHERE id=? LIMIT 1', [$editingId]) : null;
$gallery = $editingId > 0
    ? Database::safeFetchAll('SELECT id,image_path,sort_order FROM product_images WHERE product_id=? ORDER BY sort_order,id', [$editingId])
    : [];

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (!verify_csrf()) {
        $errors[] = 'Invalid security token. Refresh the page and try again.';
    } else {
        $action = (string) ($_POST['_action'] ?? 'save');
        $newFiles = [];
        $filesToDelete = [];
        try {
            if ($action === 'disable') {
                $id = max(0, (int) ($_POST['id'] ?? 0));
                if ($id < 1 || !Database::safeFetchOne('SELECT id FROM products WHERE id=? LIMIT 1', [$id])) {
                    throw new RuntimeException('Product not found.');
                }
                Database::execute('UPDATE products SET status="disabled",updated_at=NOW() WHERE id=?', [$id]);
                Security::logActivity(Auth::id(), 'product_disabled', ['product_id' => $id]);
                set_flash('success', 'Product disabled successfully.');
                redirect('admin/products.php');
            }

            $id = max(0, (int) ($_POST['id'] ?? 0));
            $name = mb_substr(trim((string) ($_POST['name'] ?? '')), 0, 190);
            $vendorId = max(0, (int) ($_POST['vendor_id'] ?? 0));
            $categoryId = max(0, (int) ($_POST['category_id'] ?? 0));
            $brandId = max(0, (int) ($_POST['brand_id'] ?? 0));
            $productType = (string) ($_POST['product_type'] ?? 'physical');
            $status = (string) ($_POST['status'] ?? 'pending');

            if ($name === '') {
                throw new RuntimeException('Product name is required.');
            }
            if (!Database::safeFetchOne('SELECT id FROM vendors WHERE id=? AND status IN ("approved","active") LIMIT 1', [$vendorId])) {
                throw new RuntimeException('Select a valid approved vendor.');
            }
            if (!Database::safeFetchOne('SELECT id FROM categories WHERE id=? AND status="active" LIMIT 1', [$categoryId])) {
                throw new RuntimeException('Select a valid category.');
            }
            if ($brandId > 0 && !Database::safeFetchOne('SELECT id FROM brands WHERE id=? AND status="active" LIMIT 1', [$brandId])) {
                throw new RuntimeException('Select a valid brand.');
            }
            if (!in_array($productType, ['physical', 'digital'], true)) {
                throw new RuntimeException('Invalid product type.');
            }
            if (!in_array($status, ['pending', 'published', 'active', 'disabled'], true)) {
                throw new RuntimeException('Invalid product status.');
            }

            $purchasePrice = max(0, (float) ($_POST['purchase_price'] ?? 0));
            $regularPrice = max(0, (float) ($_POST['regular_price'] ?? 0));
            $salePrice = max(0, (float) ($_POST['sale_price'] ?? 0));
            $flashPrice = max(0, (float) ($_POST['flash_price'] ?? 0));
            if ($regularPrice <= 0) {
                throw new RuntimeException('Regular price must be greater than zero.');
            }

            $slugSource = trim((string) ($_POST['slug'] ?? '')) ?: $name;
            $slug = unique_slug('products', $slugSource, $id ?: null);
            $sku = mb_substr(trim((string) ($_POST['sku'] ?? '')), 0, 100);
            $barcode = preg_replace('/\D+/', '', (string) ($_POST['barcode'] ?? '')) ?: admin_product_barcode($id ?: null);
            $productCode = strtoupper(mb_substr(trim((string) ($_POST['product_code'] ?? '')), 0, 100));
            if ($productCode === '') {
                $productCode = admin_product_code($id ?: null);
            }

            if (Database::safeFetchOne('SELECT id FROM products WHERE barcode=? AND id<>? LIMIT 1', [$barcode, $id])) {
                throw new RuntimeException('The barcode is already assigned to another product.');
            }
            if ($productCode !== '' && Database::safeFetchOne('SELECT id FROM products WHERE product_code=? AND id<>? LIMIT 1', [$productCode, $id])) {
                throw new RuntimeException('The product code is already assigned to another product.');
            }
            if ($sku !== '' && Database::safeFetchOne('SELECT id FROM products WHERE sku=? AND id<>? LIMIT 1', [$sku, $id])) {
                throw new RuntimeException('The SKU is already assigned to another product.');
            }

            $shortDescription = sanitize_rich_html((string) ($_POST['short_description'] ?? ''));
            $description = sanitize_rich_html((string) ($_POST['description'] ?? ''));
            $metaTitle = mb_substr(trim((string) ($_POST['meta_title'] ?? '')) ?: $name, 0, 190);
            $metaDescription = mb_substr(trim(strip_tags((string) ($_POST['meta_description'] ?? ''))), 0, 320);
            if ($metaDescription === '') {
                $metaDescription = mb_substr(trim(strip_tags($shortDescription)), 0, 160);
            }
            $metaKeywords = mb_substr(trim((string) ($_POST['meta_keywords'] ?? '')), 0, 1000);
            if ($metaKeywords === '') {
                $metaKeywords = admin_product_keywords($name, $categoryNames[$categoryId] ?? '', $brandNames[$brandId] ?? '');
            }

            $currentImage = $id > 0 ? (string) (($editing['image'] ?? '')) : '';
            $currentOgImage = $id > 0 ? (string) (($editing['og_image'] ?? '')) : '';
            if (!empty($_POST['remove_default_image'])) {
                $filesToDelete[] = $currentImage;
                $currentImage = '';
            }
            if (!empty($_POST['remove_og_image'])) {
                $filesToDelete[] = $currentOgImage;
                $currentOgImage = '';
            }

            if (!empty($_FILES['image'])) {
                $uploaded = admin_store_product_image($_FILES['image'], 'default');
                if ($uploaded) {
                    if ($currentImage !== '') {
                        $filesToDelete[] = $currentImage;
                    }
                    $currentImage = $uploaded;
                    $newFiles[] = $uploaded;
                }
            }
            if (!empty($_FILES['og_image'])) {
                $uploaded = admin_store_product_image($_FILES['og_image'], 'og');
                if ($uploaded) {
                    if ($currentOgImage !== '') {
                        $filesToDelete[] = $currentOgImage;
                    }
                    $currentOgImage = $uploaded;
                    $newFiles[] = $uploaded;
                }
            }

            $newGalleryPaths = [];
            if (!empty($_FILES['gallery_images'])) {
                $uploads = admin_normalize_multi_upload($_FILES['gallery_images']);
                if (count($uploads) > 12) {
                    throw new RuntimeException('Upload a maximum of 12 gallery images at one time.');
                }
                foreach ($uploads as $file) {
                    $uploaded = admin_store_product_image($file, 'gallery');
                    if ($uploaded) {
                        $newGalleryPaths[] = $uploaded;
                        $newFiles[] = $uploaded;
                    }
                }
            }

            $removeGalleryIds = array_values(array_filter(array_map('intval', (array) ($_POST['remove_gallery'] ?? []))));
            $stock = max(0, (int) ($_POST['stock'] ?? 0));
            $weight = max(0, (float) ($_POST['weight'] ?? 0));
            $rewardPoints = max(0, (int) ($_POST['reward_points'] ?? 0));
            $shippingCharge = max(0, (float) ($_POST['shipping_charge'] ?? 0));
            $isFeatured = !empty($_POST['is_featured']) ? 1 : 0;
            $isTrending = !empty($_POST['is_trending']) ? 1 : 0;
            $isBestSelling = !empty($_POST['is_best_selling']) ? 1 : 0;
            $videoUrl = mb_substr(trim((string) ($_POST['video_url'] ?? '')), 0, 255);

            $savedId = Database::transaction(function () use (
                $id, $vendorId, $categoryId, $brandId, $name, $slug, $sku, $barcode, $productCode,
                $productType, $purchasePrice, $regularPrice, $salePrice, $flashPrice, $stock, $weight,
                $currentImage, $videoUrl, $shortDescription, $description, $rewardPoints, $shippingCharge,
                $isFeatured, $isTrending, $isBestSelling, $status, $metaTitle, $metaDescription, $metaKeywords,
                $currentOgImage, $removeGalleryIds, $newGalleryPaths, &$filesToDelete
            ): int {
                if ($id > 0) {
                    if (!Database::fetchOne('SELECT id FROM products WHERE id=? FOR UPDATE', [$id])) {
                        throw new RuntimeException('Product not found.');
                    }
                    Database::execute(
                        'UPDATE products SET vendor_id=?,category_id=?,brand_id=?,name=?,slug=?,sku=?,barcode=?,product_code=?,product_type=?,purchase_price=?,regular_price=?,sale_price=?,flash_price=?,stock=?,weight=?,image=?,video_url=?,short_description=?,description=?,reward_points=?,shipping_charge=?,is_featured=?,is_trending=?,is_best_selling=?,status=?,meta_title=?,meta_description=?,meta_keywords=?,og_image=?,updated_at=NOW() WHERE id=?',
                        [$vendorId, $categoryId, $brandId ?: null, $name, $slug, $sku ?: null, $barcode, $productCode, $productType, $purchasePrice, $regularPrice, $salePrice, $flashPrice, $stock, $weight, $currentImage ?: null, $videoUrl ?: null, $shortDescription ?: null, $description ?: null, $rewardPoints, $shippingCharge, $isFeatured, $isTrending, $isBestSelling, $status, $metaTitle, $metaDescription ?: null, $metaKeywords ?: null, $currentOgImage ?: null, $id]
                    );
                    $productId = $id;
                } else {
                    Database::execute(
                        'INSERT INTO products (vendor_id,category_id,brand_id,name,slug,sku,barcode,product_code,product_type,purchase_price,regular_price,sale_price,flash_price,stock,weight,image,video_url,short_description,description,reward_points,shipping_charge,is_featured,is_trending,is_best_selling,status,meta_title,meta_description,meta_keywords,og_image,created_at,updated_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,NOW(),NOW())',
                        [$vendorId, $categoryId, $brandId ?: null, $name, $slug, $sku ?: null, $barcode, $productCode, $productType, $purchasePrice, $regularPrice, $salePrice, $flashPrice, $stock, $weight, $currentImage ?: null, $videoUrl ?: null, $shortDescription ?: null, $description ?: null, $rewardPoints, $shippingCharge, $isFeatured, $isTrending, $isBestSelling, $status, $metaTitle, $metaDescription ?: null, $metaKeywords ?: null, $currentOgImage ?: null]
                    );
                    $productId = Database::lastInsertId();
                }

                if ($removeGalleryIds) {
                    $placeholders = implode(',', array_fill(0, count($removeGalleryIds), '?'));
                    $existing = Database::fetchAll(
                        "SELECT image_path FROM product_images WHERE product_id=? AND id IN ({$placeholders})",
                        [$productId, ...$removeGalleryIds]
                    );
                    foreach ($existing as $row) {
                        $filesToDelete[] = (string) ($row['image_path'] ?? '');
                    }
                    Database::execute(
                        "DELETE FROM product_images WHERE product_id=? AND id IN ({$placeholders})",
                        [$productId, ...$removeGalleryIds]
                    );
                }

                $sortRow = Database::fetchOne('SELECT COALESCE(MAX(sort_order),0) max_sort FROM product_images WHERE product_id=?', [$productId]);
                $sort = (int) ($sortRow['max_sort'] ?? 0);
                foreach ($newGalleryPaths as $path) {
                    $sort++;
                    Database::execute('INSERT INTO product_images (product_id,image_path,sort_order) VALUES (?,?,?)', [$productId, $path, $sort]);
                }

                $galleryRows = Database::fetchAll('SELECT image_path FROM product_images WHERE product_id=? ORDER BY sort_order,id', [$productId]);
                $galleryJson = json_encode(array_values(array_filter(array_column($galleryRows, 'image_path'))), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
                Database::execute('UPDATE products SET gallery_json=? WHERE id=?', [$galleryJson ?: '[]', $productId]);
                return $productId;
            });

            foreach (array_unique($filesToDelete) as $path) {
                if ($path === $currentImage || $path === $currentOgImage || in_array($path, $newGalleryPaths, true)) {
                    continue;
                }
                $absolute = admin_local_upload_path((string) $path);
                if ($absolute) {
                    @unlink($absolute);
                    Database::safeExecute('DELETE FROM media_files WHERE file_path=?', [(string) $path]);
                }
            }

            Security::logActivity(Auth::id(), $id > 0 ? 'product_updated' : 'product_created', ['product_id' => $savedId]);
            set_flash('success', $id > 0 ? 'Product updated successfully.' : 'Product created successfully.');
            redirect('admin/products.php?edit=' . $savedId);
        } catch (Throwable $exception) {
            foreach ($newFiles as $path) {
                $absolute = admin_local_upload_path((string) $path);
                if ($absolute) {
                    @unlink($absolute);
                    Database::safeExecute('DELETE FROM media_files WHERE file_path=?', [(string) $path]);
                }
            }
            error_log('Product save failed: ' . $exception->getMessage());
            $errors[] = $exception instanceof RuntimeException ? $exception->getMessage() : (APP_ENV === 'production' ? 'The database rejected the product update. Check the server error log for the request details.' : $exception->getMessage());
            $editingId = max(0, (int) ($_POST['id'] ?? 0));
            $editing = array_merge($editing ?? [], $_POST);
        }
    }
}

$q = mb_substr(trim((string) ($_GET['q'] ?? '')), 0, 100);
$params = [];
$where = '1=1';
if ($q !== '') {
    $where .= ' AND (p.name LIKE ? OR p.sku LIKE ? OR p.barcode LIKE ? OR p.product_code LIKE ?)';
    $like = '%' . $q . '%';
    $params = [$like, $like, $like, $like];
}
$products = Database::safeFetchAll(
    "SELECT p.id,p.name,p.slug,p.sku,p.barcode,p.product_code,p.regular_price,p.sale_price,p.stock,p.image,p.status,p.is_featured,p.is_trending,p.is_best_selling,p.updated_at,v.shop_name,c.name category_name,b.name brand_name
     FROM products p
     LEFT JOIN vendors v ON v.id=p.vendor_id
     LEFT JOIN categories c ON c.id=p.category_id
     LEFT JOIN brands b ON b.id=p.brand_id
     WHERE {$where}
     ORDER BY p.id DESC
     LIMIT 200",
    $params
);

if ($editingId > 0 && !$editing) {
    $errors[] = 'The requested product was not found.';
    $editingId = 0;
}

require ROOT_PATH . '/app/Layouts/admin_header.php';

$form = static function (string $key, mixed $default = '') use ($editing): mixed {
    return $editing[$key] ?? $default;
};
$defaultBarcode = (string) $form('barcode', admin_product_barcode());
$defaultProductCode = (string) $form('product_code', admin_product_code());
?>
<style>
.product-image-preview{width:110px;height:90px;object-fit:contain;background:#f8f9fa;border:1px solid #dee2e6;border-radius:.65rem}.gallery-thumb{width:105px}.gallery-thumb img{width:105px;height:85px;object-fit:cover;border-radius:.5rem;border:1px solid #dee2e6}.editor-toolbar{display:flex;gap:.35rem;flex-wrap:wrap;padding:.5rem;border:1px solid #ced4da;border-bottom:0;border-radius:.375rem .375rem 0 0;background:#f8f9fa}.rich-editor{min-height:130px;border:1px solid #ced4da;border-radius:0 0 .375rem .375rem;padding:.75rem;background:#fff;overflow:auto}.rich-editor:focus{outline:0;border-color:#86b7fe;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.required-label:after{content:' *';color:#dc3545}.section-title{font-size:.82rem;letter-spacing:.06em;text-transform:uppercase;color:#6c757d;font-weight:700}.field-help{font-size:.8rem;color:#6c757d}.keyword-chip{cursor:pointer}.product-flags .badge{font-weight:500}
</style>

<div class="d-flex flex-wrap gap-3 align-items-start justify-content-between mb-4">
    <div>
        <h1 class="h3 mb-1">Products</h1>
        <p class="text-muted mb-0">Create and edit products with live vendor/category/brand selection, automatic SEO, barcode, product code and image gallery.</p>
    </div>
    <a class="btn btn-primary" href="<?= url('admin/products.php#productForm') ?>">Add new product</a>
</div>

<?php foreach ($errors as $error): ?><div class="alert alert-danger"><?= e($error) ?></div><?php endforeach; ?>

<div class="card module-card mb-4" id="productForm">
    <div class="card-header bg-white d-flex justify-content-between align-items-center">
        <strong><?= $editingId > 0 ? 'Edit product #' . $editingId : 'Add product' ?></strong>
        <?php if ($editingId > 0): ?><a class="btn btn-sm btn-outline-secondary" href="<?= url('admin/products.php#productForm') ?>">Create another</a><?php endif; ?>
    </div>
    <div class="card-body">
        <form method="post" enctype="multipart/form-data" id="adminProductForm">
            <?= csrf_field() ?>
            <input type="hidden" name="_action" value="save">
            <input type="hidden" name="id" value="<?= (int) $editingId ?>">

            <div class="section-title mb-3">Product identity</div>
            <div class="row g-3">
                <div class="col-lg-4">
                    <label class="form-label required-label" for="vendor_id">Vendor</label>
                    <select class="form-select" name="vendor_id" id="vendor_id" required>
                        <option value="">Select vendor</option>
                        <?php foreach ($vendors as $vendor): ?>
                            <option value="<?= (int) $vendor['id'] ?>" <?= (int) $form('vendor_id') === (int) $vendor['id'] ? 'selected' : '' ?>><?= e($vendor['shop_name']) ?><?= !empty($vendor['owner_name']) ? ' — ' . e($vendor['owner_name']) : '' ?></option>
                        <?php endforeach; ?>
                    </select>
                </div>
                <div class="col-lg-4">
                    <label class="form-label required-label" for="category_id">Category</label>
                    <select class="form-select" name="category_id" id="category_id" required>
                        <option value="">Select category</option>
                        <?php foreach ($categories as $category): ?>
                            <option value="<?= (int) $category['id'] ?>" data-name="<?= e($category['name']) ?>" <?= (int) $form('category_id') === (int) $category['id'] ? 'selected' : '' ?>><?= !empty($category['parent_id']) ? '↳ ' : '' ?><?= e($category['name']) ?></option>
                        <?php endforeach; ?>
                    </select>
                </div>
                <div class="col-lg-4">
                    <label class="form-label" for="brand_id">Brand</label>
                    <select class="form-select" name="brand_id" id="brand_id">
                        <option value="">No brand</option>
                        <?php foreach ($brands as $brand): ?>
                            <option value="<?= (int) $brand['id'] ?>" data-name="<?= e($brand['name']) ?>" <?= (int) $form('brand_id') === (int) $brand['id'] ? 'selected' : '' ?>><?= e($brand['name']) ?></option>
                        <?php endforeach; ?>
                    </select>
                </div>
                <div class="col-lg-8">
                    <label class="form-label required-label" for="name">Product name</label>
                    <input class="form-control" name="name" id="name" maxlength="190" value="<?= e($form('name')) ?>" required autocomplete="off">
                </div>
                <div class="col-lg-4">
                    <label class="form-label" for="product_type">Product type</label>
                    <select class="form-select" name="product_type" id="product_type">
                        <option value="physical" <?= $form('product_type', 'physical') === 'physical' ? 'selected' : '' ?>>Physical product</option>
                        <option value="digital" <?= $form('product_type') === 'digital' ? 'selected' : '' ?>>Digital product</option>
                    </select>
                </div>
                <div class="col-lg-8">
                    <label class="form-label" for="slug">Slug</label>
                    <div class="input-group"><span class="input-group-text">/product/</span><input class="form-control" name="slug" id="slug" maxlength="190" value="<?= e($form('slug')) ?>"></div>
                    <div class="form-check mt-1"><input class="form-check-input" type="checkbox" id="autoSlug" checked><label class="form-check-label field-help" for="autoSlug">Automatically update from product name</label></div>
                </div>
                <div class="col-lg-4">
                    <label class="form-label" for="status">Status</label>
                    <select class="form-select" name="status" id="status">
                        <?php foreach (['pending' => 'Pending review', 'published' => 'Published', 'active' => 'Active', 'disabled' => 'Disabled'] as $value => $label): ?>
                            <option value="<?= e($value) ?>" <?= $form('status', 'pending') === $value ? 'selected' : '' ?>><?= e($label) ?></option>
                        <?php endforeach; ?>
                    </select>
                </div>
            </div>

            <hr class="my-4">
            <div class="section-title mb-3">Codes, pricing and stock</div>
            <div class="row g-3">
                <div class="col-md-4">
                    <label class="form-label" for="sku">SKU</label>
                    <input class="form-control" name="sku" id="sku" maxlength="100" value="<?= e($form('sku')) ?>" placeholder="Example: ST-LED43">
                </div>
                <div class="col-md-4">
                    <label class="form-label" for="barcode">Barcode</label>
                    <div class="input-group"><input class="form-control" name="barcode" id="barcode" maxlength="20" inputmode="numeric" value="<?= e($defaultBarcode) ?>"><button class="btn btn-outline-secondary" type="button" id="generateBarcode">Auto</button></div>
                    <div class="field-help">A valid unique EAN-13 number is generated when blank.</div>
                </div>
                <div class="col-md-4">
                    <label class="form-label" for="product_code">Product code</label>
                    <div class="input-group"><input class="form-control text-uppercase" name="product_code" id="product_code" maxlength="100" value="<?= e($defaultProductCode) ?>"><button class="btn btn-outline-secondary" type="button" id="generateProductCode">Auto</button></div>
                </div>
                <div class="col-md-3">
                    <label class="form-label" for="purchase_price">Purchase price</label>
                    <input class="form-control" type="number" min="0" step="0.01" name="purchase_price" id="purchase_price" value="<?= e($form('purchase_price', 0)) ?>">
                </div>
                <div class="col-md-3">
                    <label class="form-label required-label" for="regular_price">Regular price</label>
                    <input class="form-control" type="number" min="0.01" step="0.01" name="regular_price" id="regular_price" value="<?= e($form('regular_price', 0)) ?>" required>
                </div>
                <div class="col-md-3">
                    <label class="form-label" for="sale_price">Sale price</label>
                    <input class="form-control" type="number" min="0" step="0.01" name="sale_price" id="sale_price" value="<?= e($form('sale_price', 0)) ?>">
                </div>
                <div class="col-md-3">
                    <label class="form-label" for="flash_price">Flash price</label>
                    <input class="form-control" type="number" min="0" step="0.01" name="flash_price" id="flash_price" value="<?= e($form('flash_price', 0)) ?>">
                </div>
                <div class="col-md-3">
                    <label class="form-label" for="stock">Stock quantity</label>
                    <input class="form-control" type="number" min="0" step="1" name="stock" id="stock" value="<?= e($form('stock', 0)) ?>">
                </div>
                <div class="col-md-3">
                    <label class="form-label" for="weight">Weight (kg)</label>
                    <input class="form-control" type="number" min="0" step="0.01" name="weight" id="weight" value="<?= e($form('weight', 0)) ?>">
                </div>
                <div class="col-md-3">
                    <label class="form-label" for="reward_points">Reward points</label>
                    <input class="form-control" type="number" min="0" step="1" name="reward_points" id="reward_points" value="<?= e($form('reward_points', 0)) ?>">
                </div>
                <div class="col-md-3">
                    <label class="form-label" for="shipping_charge">Shipping charge</label>
                    <input class="form-control" type="number" min="0" step="0.01" name="shipping_charge" id="shipping_charge" value="<?= e($form('shipping_charge', 0)) ?>">
                </div>
            </div>

            <hr class="my-4">
            <div class="section-title mb-3">Images</div>
            <div class="row g-4">
                <div class="col-lg-4">
                    <label class="form-label">Default product image</label>
                    <div class="d-flex gap-3 align-items-center mb-2">
                        <img id="defaultImagePreview" class="product-image-preview" src="<?= e($form('image') ? product_image(['image' => $form('image')]) : asset('images/gallery/product-images/01.png')) ?>" alt="Default image preview">
                        <div class="flex-grow-1"><input class="form-control" type="file" name="image" id="image" accept="image/jpeg,image/png,image/webp"><div class="field-help mt-1">JPG, PNG or WEBP. This is the main image shown in product lists.</div></div>
                    </div>
                    <?php if ($form('image')): ?><div class="form-check"><input class="form-check-input" type="checkbox" name="remove_default_image" value="1" id="removeDefaultImage"><label class="form-check-label" for="removeDefaultImage">Remove current default image</label></div><?php endif; ?>
                </div>
                <div class="col-lg-8">
                    <label class="form-label">Multiple gallery images</label>
                    <input class="form-control" type="file" name="gallery_images[]" id="gallery_images" accept="image/jpeg,image/png,image/webp" multiple>
                    <div class="field-help mt-1">Select up to 12 images per upload. Existing images remain unless marked for removal.</div>
                    <div id="newGalleryPreview" class="d-flex gap-2 flex-wrap mt-3"></div>
                    <?php if ($gallery): ?><div class="d-flex gap-3 flex-wrap mt-3"><?php foreach ($gallery as $item): ?><label class="gallery-thumb text-center"><img src="<?= e(product_image(['image' => $item['image_path']])) ?>" alt="Gallery image"><span class="form-check mt-1"><input class="form-check-input" type="checkbox" name="remove_gallery[]" value="<?= (int) $item['id'] ?>"> <span class="small text-danger">Remove</span></span></label><?php endforeach; ?></div><?php endif; ?>
                </div>
            </div>

            <hr class="my-4">
            <div class="section-title mb-3">Descriptions</div>
            <div class="row g-4">
                <div class="col-12">
                    <label class="form-label" for="shortDescriptionEditor">Short description</label>
                    <textarea class="d-none" name="short_description" id="short_description"><?= e($form('short_description')) ?></textarea>
                    <div class="editor-toolbar" data-editor-toolbar="shortDescriptionEditor"></div>
                    <div class="rich-editor" id="shortDescriptionEditor" contenteditable="true" data-target="short_description"><?= sanitize_rich_html((string) $form('short_description')) ?></div>
                    <div class="field-help mt-1">Used near the product title and as the default SEO description.</div>
                </div>
                <div class="col-12">
                    <label class="form-label" for="descriptionEditor">Detailed description</label>
                    <textarea class="d-none" name="description" id="description"><?= e($form('description')) ?></textarea>
                    <div class="editor-toolbar" data-editor-toolbar="descriptionEditor"></div>
                    <div class="rich-editor" id="descriptionEditor" contenteditable="true" data-target="description"><?= sanitize_rich_html((string) $form('description')) ?></div>
                </div>
                <div class="col-12">
                    <label class="form-label" for="video_url">Product video URL</label>
                    <input class="form-control" type="url" name="video_url" id="video_url" maxlength="255" value="<?= e($form('video_url')) ?>" placeholder="https://www.youtube.com/watch?v=...">
                </div>
            </div>

            <hr class="my-4">
            <div class="section-title mb-3">Homepage visibility</div>
            <div class="row g-3">
                <div class="col-md-4"><label class="form-label" for="is_featured">Featured product</label><select class="form-select" name="is_featured" id="is_featured"><option value="0" <?= (int) $form('is_featured', 0) === 0 ? 'selected' : '' ?>>No</option><option value="1" <?= (int) $form('is_featured', 0) === 1 ? 'selected' : '' ?>>Yes</option></select></div>
                <div class="col-md-4"><label class="form-label" for="is_trending">Trending product</label><select class="form-select" name="is_trending" id="is_trending"><option value="0" <?= (int) $form('is_trending', 0) === 0 ? 'selected' : '' ?>>No</option><option value="1" <?= (int) $form('is_trending', 0) === 1 ? 'selected' : '' ?>>Yes</option></select></div>
                <div class="col-md-4"><label class="form-label" for="is_best_selling">Best-selling product</label><select class="form-select" name="is_best_selling" id="is_best_selling"><option value="0" <?= (int) $form('is_best_selling', 0) === 0 ? 'selected' : '' ?>>No</option><option value="1" <?= (int) $form('is_best_selling', 0) === 1 ? 'selected' : '' ?>>Yes</option></select></div>
            </div>

            <hr class="my-4">
            <div class="section-title mb-3">SEO and social sharing</div>
            <div class="row g-3">
                <div class="col-lg-6">
                    <label class="form-label" for="meta_title">Meta title</label>
                    <input class="form-control" name="meta_title" id="meta_title" maxlength="190" value="<?= e($form('meta_title')) ?>">
                    <div class="form-check mt-1"><input class="form-check-input" type="checkbox" id="autoMetaTitle" checked><label class="form-check-label field-help" for="autoMetaTitle">Automatically update from product name</label></div>
                </div>
                <div class="col-lg-6">
                    <label class="form-label" for="meta_description">Meta description</label>
                    <textarea class="form-control" name="meta_description" id="meta_description" rows="3" maxlength="320"><?= e($form('meta_description')) ?></textarea>
                </div>
                <div class="col-12">
                    <label class="form-label" for="meta_keywords">Meta keywords</label>
                    <div class="input-group"><input class="form-control" name="meta_keywords" id="meta_keywords" maxlength="1000" value="<?= e($form('meta_keywords')) ?>" list="keywordSuggestions"><button class="btn btn-outline-secondary" type="button" id="useKeywordSuggestions">Auto suggest</button></div>
                    <datalist id="keywordSuggestions"><?php foreach (array_unique(array_merge(array_values($categoryNames), array_values($brandNames), ['buy online', 'best price', 'Bangladesh', 'Smart Tech OMP'])) as $suggestion): ?><option value="<?= e($suggestion) ?>"><?php endforeach; ?></datalist>
                    <div id="keywordChips" class="d-flex gap-2 flex-wrap mt-2"></div>
                </div>
                <div class="col-lg-6">
                    <label class="form-label">OG Image (Open Graph image)</label>
                    <div class="d-flex gap-3 align-items-center mb-2">
                        <img id="ogImagePreview" class="product-image-preview" src="<?= e($form('og_image') ? product_image(['image' => $form('og_image')]) : ($form('image') ? product_image(['image' => $form('image')]) : asset('images/gallery/product-images/01.png'))) ?>" alt="OG image preview">
                        <div class="flex-grow-1"><input class="form-control" type="file" name="og_image" id="og_image" accept="image/jpeg,image/png,image/webp"><div class="field-help mt-1"><strong>Purpose:</strong> this image appears when the product link is shared on Facebook, WhatsApp, Messenger, LinkedIn and similar platforms. Recommended size: 1200 × 630 pixels. The default product image is used when this is empty.</div></div>
                    </div>
                    <?php if ($form('og_image')): ?><div class="form-check"><input class="form-check-input" type="checkbox" name="remove_og_image" value="1" id="removeOgImage"><label class="form-check-label" for="removeOgImage">Remove current OG image</label></div><?php endif; ?>
                </div>
            </div>

            <div class="d-flex flex-wrap gap-2 mt-4">
                <button class="btn btn-primary btn-lg" type="submit"><?= $editingId > 0 ? 'Update product' : 'Save product' ?></button>
                <?php if ($editingId > 0): ?><a class="btn btn-outline-secondary btn-lg" href="<?= url('product/' . rawurlencode((string) $form('slug'))) ?>" target="_blank" rel="noopener">Preview product</a><?php endif; ?>
            </div>
        </form>
    </div>
</div>

<div class="card module-card">
    <div class="card-header bg-white">
        <form class="d-flex flex-wrap gap-2" method="get">
            <input class="form-control" style="max-width:420px" name="q" value="<?= e($q) ?>" placeholder="Search name, SKU, barcode or product code">
            <button class="btn btn-outline-primary">Search</button>
            <?php if ($q !== ''): ?><a class="btn btn-outline-secondary" href="<?= url('admin/products.php') ?>">Clear</a><?php endif; ?>
            <a class="btn btn-outline-secondary ms-auto" href="<?= url('api/export.php?table=products&module=products') ?>">Export CSV</a>
        </form>
    </div>
    <div class="table-responsive">
        <table class="table align-middle mb-0">
            <thead><tr><th>Product</th><th>Vendor / Category</th><th>Codes</th><th>Price</th><th>Stock</th><th>Visibility</th><th>Status</th><th>Actions</th></tr></thead>
            <tbody>
            <?php if (!$products): ?><?= table_empty(8, 'No products found.') ?><?php endif; ?>
            <?php foreach ($products as $product): ?>
                <tr>
                    <td><div class="d-flex gap-2 align-items-center"><img class="rounded border" width="58" height="50" style="object-fit:contain" src="<?= e(product_image($product)) ?>" alt=""><div><strong><?= e($product['name']) ?></strong><div class="small text-muted">#<?= (int) $product['id'] ?> · <?= e($product['brand_name'] ?? 'No brand') ?></div></div></div></td>
                    <td><?= e($product['shop_name'] ?? '—') ?><div class="small text-muted"><?= e($product['category_name'] ?? '—') ?></div></td>
                    <td><div class="small">SKU: <?= e($product['sku'] ?? '—') ?></div><div class="small">Barcode: <?= e($product['barcode'] ?? '—') ?></div><div class="small">Code: <?= e($product['product_code'] ?? '—') ?></div></td>
                    <td><?= money((float) ($product['sale_price'] ?: $product['regular_price'])) ?><div class="small text-muted">Regular <?= money($product['regular_price']) ?></div></td>
                    <td><span class="badge bg-<?= (int) $product['stock'] > 5 ? 'success' : ((int) $product['stock'] > 0 ? 'warning text-dark' : 'danger') ?>"><?= (int) $product['stock'] ?></span></td>
                    <td class="product-flags"><?php if (!empty($product['is_featured'])): ?><span class="badge bg-primary">Featured</span><?php endif; ?> <?php if (!empty($product['is_trending'])): ?><span class="badge bg-info text-dark">Trending</span><?php endif; ?> <?php if (!empty($product['is_best_selling'])): ?><span class="badge bg-success">Best seller</span><?php endif; ?></td>
                    <td><?= badge((string) $product['status']) ?></td>
                    <td class="text-nowrap"><a class="btn btn-sm btn-outline-primary" href="?edit=<?= (int) $product['id'] ?>#productForm">Edit</a> <a class="btn btn-sm btn-outline-secondary" href="<?= url('product/' . $product['slug']) ?>" target="_blank" rel="noopener">View</a> <?php if ($product['status'] !== 'disabled'): ?><form class="d-inline" method="post" onsubmit="return confirm('Disable this product?')"><?= csrf_field() ?><input type="hidden" name="_action" value="disable"><input type="hidden" name="id" value="<?= (int) $product['id'] ?>"><button class="btn btn-sm btn-outline-danger">Disable</button></form><?php endif; ?></td>
                </tr>
            <?php endforeach; ?>
            </tbody>
        </table>
    </div>
</div>

<script>
(function(){
    const form = document.getElementById('adminProductForm');
    const nameInput = document.getElementById('name');
    const slugInput = document.getElementById('slug');
    const metaTitleInput = document.getElementById('meta_title');
    const autoSlug = document.getElementById('autoSlug');
    const autoMetaTitle = document.getElementById('autoMetaTitle');
    const keywordInput = document.getElementById('meta_keywords');
    const category = document.getElementById('category_id');
    const brand = document.getElementById('brand_id');
    const keywordChips = document.getElementById('keywordChips');

    function slugify(value){
        return value.toLowerCase().trim().replace(/[^a-z0-9]+/g,'-').replace(/^-+|-+$/g,'');
    }
    function keywordSuggestions(){
        const values = [];
        const add = value => {
            value = (value || '').trim().toLowerCase();
            if(value && !values.includes(value)) values.push(value);
        };
        (nameInput.value.match(/[\p{L}\p{N}]+/gu) || []).forEach(word => { if(word.length > 1) add(word); });
        add(category.options[category.selectedIndex]?.dataset.name || '');
        add(brand.options[brand.selectedIndex]?.dataset.name || '');
        add('buy online'); add('best price'); add('bangladesh'); add('smart tech omp');
        return values.slice(0,20);
    }
    function renderKeywordChips(){
        keywordChips.innerHTML='';
        keywordSuggestions().slice(0,10).forEach(value => {
            const button=document.createElement('button');
            button.type='button';button.className='btn btn-sm btn-light border keyword-chip';button.textContent='+'+value;
            button.addEventListener('click',()=>{
                const current=keywordInput.value.split(',').map(v=>v.trim()).filter(Boolean);
                if(!current.some(v=>v.toLowerCase()===value.toLowerCase())) current.push(value);
                keywordInput.value=current.join(', ');
            });
            keywordChips.appendChild(button);
        });
    }
    function syncAutoFields(){
        if(autoSlug.checked) slugInput.value=slugify(nameInput.value);
        if(autoMetaTitle.checked) metaTitleInput.value=nameInput.value.trim();
        renderKeywordChips();
    }
    nameInput.addEventListener('input',syncAutoFields);
    category.addEventListener('change',renderKeywordChips);
    brand.addEventListener('change',renderKeywordChips);
    document.getElementById('useKeywordSuggestions').addEventListener('click',()=>{keywordInput.value=keywordSuggestions().join(', ');});

    function ean13(){
        let base='2';
        for(let i=0;i<11;i++) base+=Math.floor(Math.random()*10);
        let sum=0;
        for(let i=0;i<12;i++) sum+=Number(base[i])*(i%2===0?1:3);
        return base+((10-(sum%10))%10);
    }
    document.getElementById('generateBarcode').addEventListener('click',()=>{document.getElementById('barcode').value=ean13();});
    document.getElementById('generateProductCode').addEventListener('click',()=>{
        const now=new Date();
        const date=String(now.getFullYear()).slice(-2)+String(now.getMonth()+1).padStart(2,'0')+String(now.getDate()).padStart(2,'0');
        document.getElementById('product_code').value='PRD-'+date+'-'+Math.random().toString(36).slice(2,8).toUpperCase();
    });

    function previewSingle(input, preview){
        input.addEventListener('change',()=>{
            const file=input.files && input.files[0];
            if(file) preview.src=URL.createObjectURL(file);
        });
    }
    previewSingle(document.getElementById('image'),document.getElementById('defaultImagePreview'));
    previewSingle(document.getElementById('og_image'),document.getElementById('ogImagePreview'));
    document.getElementById('gallery_images').addEventListener('change',function(){
        const box=document.getElementById('newGalleryPreview');box.innerHTML='';
        Array.from(this.files || []).slice(0,12).forEach(file=>{
            const img=document.createElement('img');img.className='gallery-thumb';img.style.width='105px';img.style.height='85px';img.style.objectFit='cover';img.style.borderRadius='.5rem';img.style.border='1px solid #dee2e6';img.src=URL.createObjectURL(file);box.appendChild(img);
        });
    });

    const toolbarButtons=[
        ['Bold','bold'],['Italic','italic'],['Underline','underline'],['H2','formatBlock','H2'],['H3','formatBlock','H3'],['Bullets','insertUnorderedList'],['Numbers','insertOrderedList'],['Link','createLink'],['Clear','removeFormat']
    ];
    document.querySelectorAll('[data-editor-toolbar]').forEach(toolbar=>{
        const editor=document.getElementById(toolbar.dataset.editorToolbar);
        toolbarButtons.forEach(item=>{
            const button=document.createElement('button');button.type='button';button.className='btn btn-sm btn-outline-secondary';button.textContent=item[0];
            button.addEventListener('click',()=>{
                editor.focus();
                let value=item[2] || null;
                if(item[1]==='createLink') value=prompt('Enter a safe URL (https://...)') || '';
                if(item[1]==='formatBlock') document.execCommand(item[1],false,value); else if(value!=='' || item[1]!=='createLink') document.execCommand(item[1],false,value);
                document.getElementById(editor.dataset.target).value=editor.innerHTML;
            });
            toolbar.appendChild(button);
        });
        editor.addEventListener('input',()=>{document.getElementById(editor.dataset.target).value=editor.innerHTML;});
    });

    form.addEventListener('submit',()=>{
        document.querySelectorAll('.rich-editor').forEach(editor=>{document.getElementById(editor.dataset.target).value=editor.innerHTML;});
        if(!document.getElementById('barcode').value) document.getElementById('barcode').value=ean13();
        if(!document.getElementById('product_code').value) document.getElementById('generateProductCode').click();
    });

    renderKeywordChips();
    if(!slugInput.value && nameInput.value) slugInput.value=slugify(nameInput.value);
    if(!metaTitleInput.value && nameInput.value) metaTitleInput.value=nameInput.value;
})();
</script>
<?php require ROOT_PATH . '/app/Layouts/admin_footer.php'; ?>
