<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Product;
use App\Models\Category;
use App\Models\Unit;
use App\Models\Tax;
use App\Models\Brand;
use App\Models\Attribute;
use App\Models\AttributeValue;
use App\Models\StockMovement;
use App\Models\VariantStockMovement;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\View\View;
use Illuminate\Http\RedirectResponse;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use App\Models\ProductMedia;
use App\Models\ProductImport;
use App\Jobs\ProcessProductImportJob;
use App\Services\ImageService;

class ProductController extends Controller
{
    public function __construct(
        protected ImageService $imageService
    ) {}

    /**
     * Display a listing of products
     */
    public function index(Request $request): View
    {
        $this->authorize('products.view');
        $allowedPerPage = [10, 20, 50, 100];
        $perPage = (int) $request->input('per_page', 10);
        if (!in_array($perPage, $allowedPerPage, true)) {
            $perPage = 10;
        }
        $query = Product::with(['category', 'unit', 'tax', 'brand']);

        // Filter by product type (for tabs)
        $productType = $request->get('type', 'single');
        if (in_array($productType, ['single', 'variant'])) {
            if ($productType === 'single') {
                // Single products: parent_id IS NULL AND product_type = 'single'
                $query->whereNull('parent_id')
                      ->where('product_type', 'single');
            } else {
                // Variant parent products: parent_id IS NULL AND product_type = 'variant'
                $query->whereNull('parent_id')
                      ->where('product_type', 'variant');
            }
        } else {
            $query->whereNull('parent_id')
                  ->where('product_type', 'single');
            $productType = 'single';
        }

        // For variant parent products, load variants count and actual variants
        if ($productType === 'variant') {
            $query->withCount(['variants' => function($query) {
                $query->where('is_active', true);
            }])->with(['variants' => function($query) {
                $query->where('is_active', true)
                      ->with(['attributeValues.attribute', 'category', 'unit', 'tax', 'brand'])
                      ->orderBy('name');
            }]);
        }

        // Filter by category
        if ($request->filled('category_id')) {
            $query->where('category_id', $request->category_id);
        }

        // Filter by purchase price status
        if ($request->filled('purchase_price_status')) {
            if ($request->purchase_price_status === 'missing') {
                $query->missingPurchasePrice();
            } elseif ($request->purchase_price_status === 'has_price') {
                $query->withPurchasePrice();
            }
        }

        // Search by name, tags, barcode, description, category, or slug
        if ($request->filled('search')) {
            $search = $request->search;
            if ($productType === 'variant') {
                // Search in parent products and their variants
                $query->where(function ($q) use ($search) {
                    $q->where(function ($parentQuery) use ($search) {
                        $parentQuery->where('name', 'like', "%{$search}%")
                          ->orWhere('barcode', 'like', "%{$search}%")
                          ->orWhere('slug', 'like', "%{$search}%")
                          ->orWhere('tags', 'like', "%{$search}%")
                          ->orWhere('short_desc', 'like', "%{$search}%")
                          ->orWhere('long_desc', 'like', "%{$search}%")
                          ->orWhereHas('category', function ($categoryQuery) use ($search) {
                              $categoryQuery->where('name', 'like', "%{$search}%");
                          });
                    })
                    ->orWhereHas('variants', function ($variantQuery) use ($search) {
                        $variantQuery->where('name', 'like', "%{$search}%")
                            ->orWhere('barcode', 'like', "%{$search}%")
                            ->orWhere('slug', 'like', "%{$search}%")
                            ->orWhere('tags', 'like', "%{$search}%")
                            ->orWhere('short_desc', 'like', "%{$search}%")
                            ->orWhere('long_desc', 'like', "%{$search}%")
                            ->orWhereHas('category', function ($categoryQuery) use ($search) {
                                $categoryQuery->where('name', 'like', "%{$search}%");
                            });
                    });
                });
            } else {
                // Search for single products
                $query->where(function ($q) use ($search) {
                    $q->where('name', 'like', "%{$search}%")
                      ->orWhere('barcode', 'like', "%{$search}%")
                      ->orWhere('slug', 'like', "%{$search}%")
                      ->orWhere('tags', 'like', "%{$search}%")
                      ->orWhere('short_desc', 'like', "%{$search}%")
                      ->orWhere('long_desc', 'like', "%{$search}%")
                      ->orWhereHas('category', function ($categoryQuery) use ($search) {
                          $categoryQuery->where('name', 'like', "%{$search}%");
                      });
                });
            }
        }

        // Filter by status
        if ($request->filled('status')) {
            if ($request->status === 'active') {
                $query->where('is_active', true);
            } elseif ($request->status === 'inactive') {
                $query->where('is_active', false);
            }
        }

        // Filter by verification
        if ($request->filled('verified')) {
            if ($request->verified === 'verified') {
                $query->where('is_verified', true);
            } elseif ($request->verified === 'unverified') {
                $query->where('is_verified', false);
            }
        }

        // Filter by channel visibility
        if ($request->filled('channel_visibility')) {
            if (in_array($request->channel_visibility, Product::CHANNEL_VISIBILITIES, true)) {
                $query->where('channel_visibility', $request->channel_visibility);
            }
        }

        // Sorting
        $sortBy = $request->get('sort', 'created_at');
        $sortOrder = $request->get('order', 'desc');
        
        // Validate sort order
        $sortOrder = in_array(strtolower($sortOrder), ['asc', 'desc']) ? strtolower($sortOrder) : 'desc';
        
        // Handle different sort fields
        switch ($sortBy) {
            case 'price':
                $query->orderBy('price', $sortOrder);
                break;
            case 'category':
                $query->orderBy('category_id', $sortOrder);
                break;
            case 'status':
                $query->orderBy('is_active', $sortOrder === 'desc' ? 'desc' : 'asc');
                break;
            case 'name':
                $query->orderBy('name', $sortOrder);
                break;
            case 'stock':
                $query->orderBy('current_stock', $sortOrder);
                break;
            default:
                // Default: Sort by recently added (created_at desc)
                $query->orderBy('created_at', 'desc');
                break;
        }

        $products = $query->paginate($perPage)->withQueryString();
        $categories = Category::all(['id', 'name']);

        // Statistics for purchase price coverage
        $totalProducts = Product::count();
        $missingPurchasePrice = Product::missingPurchasePrice()->count();
        $coveragePercent = $totalProducts > 0 ? round((($totalProducts - $missingPurchasePrice) / $totalProducts) * 100, 2) : 0;

        // Product type counts for tab badges (respect current active filters/search)
        $singleCountQuery = Product::whereNull('parent_id')
            ->where('product_type', 'single');
        $variantCountQuery = Product::whereNull('parent_id')
            ->where('product_type', 'variant');

        foreach ([$singleCountQuery, $variantCountQuery] as $countQuery) {
            // Filter by category
            if ($request->filled('category_id')) {
                $countQuery->where('category_id', $request->category_id);
            }

            // Filter by purchase price status
            if ($request->filled('purchase_price_status')) {
                if ($request->purchase_price_status === 'missing') {
                    $countQuery->missingPurchasePrice();
                } elseif ($request->purchase_price_status === 'has_price') {
                    $countQuery->withPurchasePrice();
                }
            }

            // Filter by status
            if ($request->filled('status')) {
                if ($request->status === 'active') {
                    $countQuery->where('is_active', true);
                } elseif ($request->status === 'inactive') {
                    $countQuery->where('is_active', false);
                }
            }

            // Filter by verification
            if ($request->filled('verified')) {
                if ($request->verified === 'verified') {
                    $countQuery->where('is_verified', true);
                } elseif ($request->verified === 'unverified') {
                    $countQuery->where('is_verified', false);
                }
            }

            // Filter by channel visibility
            if ($request->filled('channel_visibility')) {
                if (in_array($request->channel_visibility, Product::CHANNEL_VISIBILITIES, true)) {
                    $countQuery->where('channel_visibility', $request->channel_visibility);
                }
            }
        }

        // Search for single count
        if ($request->filled('search')) {
            $search = $request->search;

            $singleCountQuery->where(function ($q) use ($search) {
                $q->where('name', 'like', "%{$search}%")
                    ->orWhere('barcode', 'like', "%{$search}%")
                    ->orWhere('slug', 'like', "%{$search}%")
                    ->orWhere('tags', 'like', "%{$search}%")
                    ->orWhere('short_desc', 'like', "%{$search}%")
                    ->orWhere('long_desc', 'like', "%{$search}%")
                    ->orWhereHas('category', function ($categoryQuery) use ($search) {
                        $categoryQuery->where('name', 'like', "%{$search}%");
                    });
            });

            // Search for variant count
            $variantCountQuery->where(function ($q) use ($search) {
                $q->where(function ($parentQuery) use ($search) {
                    $parentQuery->where('name', 'like', "%{$search}%")
                        ->orWhere('barcode', 'like', "%{$search}%")
                        ->orWhere('slug', 'like', "%{$search}%")
                        ->orWhere('tags', 'like', "%{$search}%")
                        ->orWhere('short_desc', 'like', "%{$search}%")
                        ->orWhere('long_desc', 'like', "%{$search}%")
                        ->orWhereHas('category', function ($categoryQuery) use ($search) {
                            $categoryQuery->where('name', 'like', "%{$search}%");
                        });
                })->orWhereHas('variants', function ($variantQuery) use ($search) {
                    $variantQuery->where('name', 'like', "%{$search}%")
                        ->orWhere('barcode', 'like', "%{$search}%")
                        ->orWhere('slug', 'like', "%{$search}%")
                        ->orWhere('tags', 'like', "%{$search}%")
                        ->orWhere('short_desc', 'like', "%{$search}%")
                        ->orWhere('long_desc', 'like', "%{$search}%")
                        ->orWhereHas('category', function ($categoryQuery) use ($search) {
                            $categoryQuery->where('name', 'like', "%{$search}%");
                        });
                });
            });
        }

        $singleCount = $singleCountQuery->count();
        $variantCount = $variantCountQuery->count();

        // Get default visible columns based on product type
        $hasStockColumn = true;
        $defaultVisible = ['image', 'name', 'category', 'tags', 'shipping_days', 'price', 'status', 'verified', 'channel_visibility', 'actions'];
        if ($hasStockColumn) {
            $defaultVisible = array_merge(
                array_slice($defaultVisible, 0, 4),
                ['stock'],
                array_slice($defaultVisible, 4)
            );
        }

        // Get all available columns
        $availableColumns = ['image', 'id', 'name', 'sku', 'category', 'brand', 'hsn', 'shipping_days', 'price', 'mrp', 'purchase_price', 'wholesale_price', 'status', 'verified', 'channel_visibility', 'actions'];
        if ($hasStockColumn) {
            $availableColumns = array_merge(
                array_slice($availableColumns, 0, array_search('price', $availableColumns) + 1),
                ['stock', 'opening_stock'],
                array_slice($availableColumns, array_search('price', $availableColumns) + 1)
            );
        }
        $availableColumns = array_merge($availableColumns, ['unit', 'tax', 'tags', 'short_desc', 'featured', 'prebooking', 'created_at']);

        // Load user preferences from database
        $user = auth()->user();
        $visibleColumns = $defaultVisible;
        if ($user) {
            $userPreferences = $user->getProductColumnPreferences($defaultVisible, $availableColumns);
            if (!empty($userPreferences)) {
                $visibleColumns = array_values($userPreferences); // Ensure indexed array
            }
        }
        
        // Ensure image and actions are always visible
        if (!in_array('image', $visibleColumns)) {
            $visibleColumns[] = 'image';
        }
        if (!in_array('actions', $visibleColumns)) {
            $visibleColumns[] = 'actions';
        }
        $visibleColumns = array_values(array_unique($visibleColumns));

        return view('admin.products.index', compact(
            'products',
            'categories',
            'totalProducts',
            'missingPurchasePrice',
            'coveragePercent',
            'productType',
            'singleCount',
            'variantCount',
            'perPage',
            'allowedPerPage',
            'visibleColumns',
            'defaultVisible',
            'availableColumns'
        ));
    }

    /**
     * Show the form for creating a new product
     */
    public function create(): View
    {
        $categories = Category::where('is_active', 1)->get();
        $units = Unit::all();
        $taxes = Tax::where('is_active', 1)->get();
        $brands = Brand::orderBy('name')->get(); // Order brands by name for consistency

        return view('admin.products.create', compact('categories', 'units', 'taxes', 'brands'));
    }

    /**
     * Store a newly created product
     */
    public function store(Request $request): RedirectResponse
    {
        $request->validate([
            'category_id' => 'required|exists:categories,id',
            'unit_id' => 'nullable|exists:units,id',
            'tax_id' => 'nullable|exists:taxes,id',
            'brand_id' => 'nullable|exists:brands,id',
            'name' => ['required', 'string', $this->maxLengthRule(255)],
            'slug' => ['nullable', 'string', $this->maxLengthRule(191), 'unique:products'],
            'barcode' => ['nullable', 'string', $this->maxLengthRule(8), 'unique:products'],
            'hsn_code' => ['nullable', 'string', $this->maxLengthRule(50)],
            'shipping_days' => ['nullable', 'integer', $this->integerRangeRule(0)],
            'price' => ['required', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'purchase_price' => ['required', 'numeric', $this->decimalRangeRule(0, 999999.99)], // Required for new products
            'wholesale_price' => ['nullable', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'mrp' => ['nullable', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'opening_stock' => ['required', 'integer', $this->integerRangeRule(0)],
            'short_desc' => 'nullable|string',
            'long_desc' => 'nullable|string',
            'image' => 'nullable|image|mimes:jpeg,png,jpg,gif,webp|max:5120',
            'additional_images' => ['nullable', 'array', $this->arrayMaxCountRule(5)],
            'additional_images.*' => 'image|mimes:jpeg,png,jpg,gif,webp|max:2048',
            'videos' => ['nullable', 'array', $this->arrayMaxCountRule(2)],
            'videos.*' => 'file|mimetypes:video/mp4,video/webm,video/quicktime,video/x-msvideo|max:51200',
            'is_active' => 'boolean',
            'is_verified' => 'boolean',
            'channel_visibility' => ['required', 'string', \Illuminate\Validation\Rule::in(\App\Models\Product::CHANNEL_VISIBILITIES)],
            'is_featured' => 'boolean',
            'is_prebooking' => 'boolean',
            'tags' => ['nullable', 'string', $this->maxLengthRule(500)],
        ]);

        $data = $request->all();
        $data['channel_visibility'] = $request->input('channel_visibility', Product::CHANNEL_BOTH);
        
        // Auto-generate slug from product name if not provided
        if (empty($data['slug'])) {
            $data['slug'] = \Illuminate\Support\Str::slug($data['name']);
            
            // Ensure slug is unique
            $originalSlug = $data['slug'];
            $counter = 1;
            while (\App\Models\Product::where('slug', $data['slug'])->exists()) {
                $data['slug'] = $originalSlug . '-' . $counter;
                $counter++;
            }
        }

        if(empty($data['barcode'])){
            $data['barcode'] = $this->generateBarcode(Product::class);
        }

        // Set current_stock to opening_stock initially
        $data['current_stock'] = $data['opening_stock'] ?? 0;

        $product = Product::create($data);

        // Handle image upload (after create so we have product id for folder)
        if ($request->hasFile('image')) {
            $imageResult = $this->imageService->processProductImageVariants($request->file('image'), $product->id);
            $product->update([
                'image_path' => $imageResult['original'],
                'image' => $imageResult,
            ]);
        }

        // Handle additional images upload
        if ($request->hasFile('additional_images')) {
            $displayOrder = 0;
            foreach ($request->file('additional_images') as $image) {
                $path = $image->store("products/media/images/{$product->id}", 'public');
                ProductMedia::create([
                    'product_id' => $product->id,
                    'type' => 'image',
                    'file_path' => $path,
                    'display_order' => $displayOrder++,
                ]);
            }
        }

        // Handle videos upload
        if ($request->hasFile('videos')) {
            $displayOrder = 0;
            foreach ($request->file('videos') as $video) {
                $path = $video->store("products/media/videos/{$product->id}", 'public');
                ProductMedia::create([
                    'product_id' => $product->id,
                    'type' => 'video',
                    'file_path' => $path,
                    'display_order' => $displayOrder++,
                ]);
            }
        }

        // Create initial stock movement if opening stock > 0
        if ($product->opening_stock > 0) {
            \App\Models\StockMovement::create([
                'product_id' => $product->id,
                'type' => \App\Models\StockMovement::TYPE_OPENING_STOCK,
                'quantity' => $product->opening_stock,
                'notes' => 'Opening stock',
                'created_by' => auth()->check() ? auth()->id() : 1,
            ]);

            // Update current stock (observer should handle this, but ensure it's updated)
            $product->refresh();
            $product->updateCurrentStock();
        }

        return redirect()->route('admin.products.index')
            ->with('success', 'Product created successfully.');
    }

    /**
     * Display the specified product
     */
    public function show(Product $product): View
    {
        $product->load(['category', 'unit', 'tax', 'stockMovements']);

        // Calculate stock summary
        $openingStock = $product->stockMovements
            ->where('type', StockMovement::TYPE_OPENING_STOCK)
            ->sum('quantity');

        $totalRestocked = $product->stockMovements
            ->where('type', StockMovement::TYPE_RESTOCK)
            ->sum('quantity');

        $totalSold = $product->stockMovements
            ->where('type', StockMovement::TYPE_SALE)
            ->sum('quantity');

        // Prefer stored current_stock, fallback to movements sum
        $currentStock = $product->current_stock ?? $product->stockMovements->sum('quantity');

        return view('admin.products.show', compact(
            'product',
            'openingStock',
            'totalRestocked',
            'totalSold',
            'currentStock'
        ));
    }

    /**
     * Show the form for editing the specified product
     */
    public function edit(Product $product): View
    {
        $categories = Category::where('is_active', 1)->get();
        $units = Unit::all();
        $taxes = Tax::where('is_active', 1)->get();
        $brands = Brand::all();
        
        // Load media relationships
        $product->load('media');

        return view('admin.products.edit', compact('product', 'categories', 'units', 'taxes', 'brands'));
    }

    /**
     * Update the specified product
     */
    public function update(Request $request, Product $product): RedirectResponse
    {
        $validationRules = [
            'category_id' => 'required|exists:categories,id',
            'unit_id' => 'nullable|exists:units,id',
            'tax_id' => 'nullable|exists:taxes,id',
            'brand_id' => 'nullable|exists:brands,id',
            'name' => ['required', 'string', $this->maxLengthRule(255)],
            'slug' => ['nullable', 'string', $this->maxLengthRule(191), 'unique:products,slug,' . $product->id],
            'barcode' => ['nullable', 'string', $this->maxLengthRule(8), 'unique:products,barcode,' . $product->id],
            'hsn_code' => ['nullable', 'string', $this->maxLengthRule(50)],
            'shipping_days' => ['nullable', 'integer', $this->integerRangeRule(0)],
            'tags' => ['nullable', 'string', $this->maxLengthRule(500)],
            'price' => ['required', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'purchase_price' => ['nullable', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'wholesale_price' => ['nullable', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'mrp' => ['nullable', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'short_desc' => 'nullable|string',
            'long_desc' => 'nullable|string',
            'image' => 'nullable|image|mimes:jpeg,png,jpg,gif,webp|max:5120',
            'additional_images' => ['nullable', 'array', $this->arrayMaxCountRule(5)],
            'additional_images.*' => 'image|mimes:jpeg,png,jpg,gif,webp|max:2048',
            'videos' => ['nullable', 'array', $this->arrayMaxCountRule(2)],
            'videos.*' => 'mimes:mp4,webm,mov,avi|max:51200',
            'existing_images' => 'nullable|array',
            'existing_images.*' => 'exists:product_media,id',
            'existing_videos' => 'nullable|array',
            'existing_videos.*' => 'exists:product_media,id',
            'delete_media' => 'nullable|array',
            'delete_media.*' => 'exists:product_media,id',
            'is_active' => 'boolean',
            'is_verified' => 'boolean',
            'channel_visibility' => ['required', 'string', \Illuminate\Validation\Rule::in(\App\Models\Product::CHANNEL_VISIBILITIES)],
            'is_featured' => 'boolean',
            'is_prebooking' => 'boolean',
        ];

        $data = $request->all();
        $data['channel_visibility'] = $request->input('channel_visibility', $product->channel_visibility ?? Product::CHANNEL_BOTH);
        // Only pass fillable attributes to update (keeps tags and avoids overwriting with null)
        $data = array_intersect_key($data, array_flip($product->getFillable()));
        $data['tags'] = $request->input('tags') ?? $product->tags;
        
        // Auto-generate slug from product name if not provided or if name changed
        if (empty($data['slug']) || $data['name'] !== $product->name) {
            $newSlug = \Illuminate\Support\Str::slug($data['name']);
            
            // If name changed, generate new slug, otherwise keep existing
            if ($data['name'] !== $product->name) {
                // Ensure slug is unique
                $originalSlug = $newSlug;
                $counter = 1;
                while (\App\Models\Product::where('slug', $newSlug)->where('id', '!=', $product->id)->exists()) {
                    $newSlug = $originalSlug . '-' . $counter;
                    $counter++;
                }
                $data['slug'] = $newSlug;
            } else {
                // Name didn't change, keep existing slug
                $data['slug'] = $product->slug;
            }
        }

        // Handle image upload
        if ($request->hasFile('image')) {
            $this->imageService->deleteProductImageFolder($product->id, $product->image_path);
            $imageResult = $this->imageService->processProductImageVariants($request->file('image'), $product->id);
            $data['image_path'] = $imageResult['original'];
            $data['image'] = $imageResult;
        }

        $product->update($data);

        // Handle existing media deletion (removed from form or explicitly deleted)
        $deleteMediaIds = $request->input('delete_media', []);
        $existingImageIds = $request->input('existing_images', []);
        $existingVideoIds = $request->input('existing_videos', []);
        
        // Delete media that was explicitly marked for deletion via remove button
        if (!empty($deleteMediaIds)) {
            $product->media()->whereIn('id', $deleteMediaIds)->get()->each(function ($media) {
                Storage::disk('public')->delete($media->file_path);
                $media->delete();
            });
        }
        
        // Get all current media IDs
        $allCurrentImageIds = $product->media()->images()->pluck('id')->toArray();
        $allCurrentVideoIds = $product->media()->videos()->pluck('id')->toArray();
        
        // Only process deletions if existing_images/existing_videos are provided in the request
        // This means the media section was rendered and submitted
        if ($request->has('existing_images')) {
            // Find images that exist in database but are not in the existing_images array
            // These should be deleted (user removed them from the form)
            $imagesToDelete = array_diff($allCurrentImageIds, $existingImageIds);
            if (!empty($imagesToDelete)) {
                $product->media()->images()->whereIn('id', $imagesToDelete)->get()->each(function ($media) {
                    Storage::disk('public')->delete($media->file_path);
                    $media->delete();
                });
            }
        }
        
        if ($request->has('existing_videos')) {
            // Find videos that exist in database but are not in the existing_videos array
            $videosToDelete = array_diff($allCurrentVideoIds, $existingVideoIds);
            if (!empty($videosToDelete)) {
                $product->media()->videos()->whereIn('id', $videosToDelete)->get()->each(function ($media) {
                    Storage::disk('public')->delete($media->file_path);
                    $media->delete();
                });
            }
        }

        // Handle new additional images upload
        if ($request->hasFile('additional_images')) {
            $maxDisplayOrder = $product->media()->images()->max('display_order') ?? -1;
            $displayOrder = $maxDisplayOrder + 1;
            foreach ($request->file('additional_images') as $image) {
                $path = $image->store("products/media/images/{$product->id}", 'public');
                ProductMedia::create([
                    'product_id' => $product->id,
                    'type' => 'image',
                    'file_path' => $path,
                    'display_order' => $displayOrder++,
                ]);
            }
        }

        // Handle new videos upload
        if ($request->hasFile('videos')) {
            $maxDisplayOrder = $product->media()->videos()->max('display_order') ?? -1;
            $displayOrder = $maxDisplayOrder + 1;
            foreach ($request->file('videos') as $video) {
                $path = $video->store("products/media/videos/{$product->id}", 'public');
                ProductMedia::create([
                    'product_id' => $product->id,
                    'type' => 'video',
                    'file_path' => $path,
                    'display_order' => $displayOrder++,
                ]);
            }
        }

        // Refresh media relationship for next view
        $product->load('media');

        return redirect()->route('admin.products.edit', $product->id)
            ->with('success', 'Product updated successfully.');
    }

    /**
     * Remove the specified product
     */
    public function destroy(Product $product): RedirectResponse
    {
        // Delete main image folder (and legacy single file if any)
        $this->imageService->deleteProductImageFolder($product->id, $product->image_path);

        // Delete all associated media files
        $product->media()->each(function ($media) {
            Storage::disk('public')->delete($media->file_path);
            $media->delete();
        });

        $product->delete();

        return redirect()->route('admin.products.index')
            ->with('success', 'Product deleted successfully.');
    }

    /**
     * Show stock history for a product
     */
    public function stockHistory(Product $product): View
    {
        $stockMovements = $product->stockMovements()
            ->with('creator')
            ->orderBy('created_at', 'desc')
            ->paginate(20);

        return view('admin.products.stock-history', compact('product', 'stockMovements'));
    }

    /**
     * Show stock history for a product variant
     */
    public function variantStockHistory(Product $variant): View
    {
        if (is_null($variant->parent_id)) {
            return redirect()->route('admin.products.index')
                ->with('error', 'This is not a variant product.');
        }
        
        $variant->load('parent', 'attributeValues.attribute');
        
        $stockMovements = VariantStockMovement::where('product_id', $variant->id)
            ->with('creator')
            ->orderBy('created_at', 'desc')
            ->paginate(20);

        return view('admin.products.variants.stock-history', compact('variant', 'stockMovements'));
    }

    /**
     * Download sample import file
     */
    public function downloadSample(): StreamedResponse
    {
        $filename = 'products_import_sample.csv';
        
        $headers = [
            'Content-Type' => 'text/csv',
            'Content-Disposition' => 'attachment; filename="' . $filename . '"',
        ];

        $callback = function() {
            $file = fopen('php://output', 'w');
            
            // Add BOM for UTF-8 (helps with Excel)
            fprintf($file, chr(0xEF).chr(0xBB).chr(0xBF));
            
            // CSV Headers - matching import format
            fputcsv($file, [
                'product_type',
                'name',
                'category_name',
                'tags',
                'sku',
                'price',
                'mrp',
                'purchase_price',
                'wholesale_price',
                'opening_stock',
                'barcode',
                'unit_name',
                'short_desc',
                'long_desc',
                'is_active',
                'is_featured',
                'is_prebooking',
                'image_name',
                'variant_attributes',
                'variant_sku',
                'variant_price',
                'variant_mrp',
                'variant_purchase_price',
                'variant_wholesale_price',
                'variant_opening_stock',
                'variant_barcode',
                'variant_image_name'
            ]);

            // Sample data row 1: Single product
            fputcsv($file, [
                'single',
                'Sample Product 1',
                'Earrings', // Example category name - must match existing category
                'jewelry, gold, earrings',
                'PROD1-001', // SKU (optional, auto-generated if empty)
                '100.00',
                '120.00',
                '90.00',
                '95.00',
                '50',
                '45679876',
                'pc', // Example unit name - must match existing unit
                'Sample short description for product 1',
                'This is a sample long description for product 1. It can contain multiple sentences and detailed information about the product.',
                '1',
                '0',
                '0',
                'sample_product_1.jpg', // Optional: image file name from /public/uploads/imports/products/
                '', // variant_attributes - empty for single products
                '', // variant_sku
                '', // variant_price
                '', // variant_mrp
                '', // variant_purchase_price
                '', // variant_wholesale_price
                '', // variant_opening_stock
                '', // variant_barcode
                ''  // variant_image_name
            ]);

            // Sample data rows 2-4: Variant product (multiple rows with same product name)
            // Row 2: Variant 1
            fputcsv($file, [
                'variant',
                'Sample Variant Product',
                'Rings', // Example category name
                'ring, gold, variant',
                'VAR-PARENT-001', // SKU for parent (optional, auto-generated if empty)
                '1000.00', // Base price (may be overridden by variant_price)
                '1200.00', // Base MRP
                '0',
                '0',
                '0', // Product-level stock is 0 for variant products
                '34521232',
                'pc',
                'Sample variant product description',
                'This is a variant product with multiple size and color options.',
                '1',
                '1',
                '0',
                'variant_product.jpg', // Product image
                'Large,Gold', // variant_attributes: comma-separated attribute values (e.g., Size:Large, Color:Gold)
                'VAR-001', // variant_sku (optional, will be auto-generated if empty)
                '1100.00', // variant_price
                '1300.00', // variant_mrp
                '1000.00', // variant_purchase_price
                '1050.00', // variant_wholesale_price
                '25', // variant_opening_stock
                '12398989', // variant_barcode (optional)
                'variant_large_gold.jpg' // variant_image_name (optional)
            ]);

            // Row 3: Variant 2
            fputcsv($file, [
                'variant',
                'Sample Variant Product', // Same product name
                'Rings',
                'ring, gold, variant',
                'VAR-PARENT-001', // SKU for parent (same as first variant row)
                '1000.00',
                '1200.00',
                '0',
                '0',
                '0',
                '78651212',
                'pc',
                'Sample variant product description',
                'This is a variant product with multiple size and color options.',
                '1',
                '1',
                '0',
                'variant_product.jpg',
                'Large,Silver', // Different variant attributes
                'VAR-002',
                '1050.00',
                '1250.00',
                '900.00', // variant_purchase_price
                '1000.00', // variant_wholesale_price
                '30',
                '99998989',
                'variant_large_silver.jpg'
            ]);

            // Row 4: Variant 3
            fputcsv($file, [
                'variant',
                'Sample Variant Product', // Same product name
                'Rings',
                'ring, gold, variant',
                'VAR-PARENT-001', // SKU for parent (same as other variant rows)
                '1000.00',
                '1200.00',
                '0',
                '0',
                '0',
                '67531232',
                'pc',
                'Sample variant product description',
                'This is a variant product with multiple size and color options.',
                '1',
                '1',
                '0',
                'variant_product.jpg',
                'Small,Gold', // Different variant attributes
                'VAR-003',
                '950.00',
                '1150.00',
                '800.00', // variant_purchase_price
                '900.00', // variant_wholesale_price
                '20',
                '99889988',
                'variant_small_gold.jpg'
            ]);
            
            fclose($file);
        };

        return response()->stream($callback, 200, $headers);
    }

    /**
     * Download categories as CSV for import reference
     */
    public function downloadCategories(): StreamedResponse
    {
        $this->authorize('products.create');

        $headers = [
            'Content-Type' => 'text/csv',
            'Content-Disposition' => 'attachment; filename="categories.csv"',
        ];

        $categories = Category::with('parent')
            ->orderBy('parent_id')
            ->orderBy('sort_order')
            ->orderBy('name')
            ->get(['id', 'name', 'parent_id', 'sort_order', 'is_active']);

        $callback = function () use ($categories) {
            $output = fopen('php://output', 'w');
            fputcsv($output, ['name', 'parent_category_name', 'sort_orde', 'is_active']);

            foreach ($categories as $category) {
                fputcsv($output, [
                    $category->name,
                    $category->parent ? $category->parent->name : '',
                    $category->sort_order ?? 0,
                    $category->is_active ? 1 : 0
                ]);
            }

            fclose($output);
        };

        return response()->stream($callback, 200, $headers);
    }

    /**
     * Show import products page
     */
    public function showImport(): View
    {
        $this->authorize('products.import');
        // Ensure enough memory if page or any component triggers image processing
        @ini_set('memory_limit', '512M');
        return view('admin.products.import-products');
    }

    /**
     * Import products from CSV (background): store file, queue job, redirect to report.
     */
    public function import(Request $request): RedirectResponse
    {
        $request->validate([
            'import_file' => 'required|file|mimes:csv,txt|max:5120', // 5MB max
        ]);

        $file = $request->file('import_file');
        $dir = 'product-imports';
        $filename = date('Y-m-d') . '-' . \Illuminate\Support\Str::random(16) . '.csv';
        $path = $file->storeAs($dir, $filename);
        // Ensure path is stored as expected (e.g. "product-imports/2026-02-05-xxx.csv")
        if (is_string($path)) {
            $path = trim($path, '/\\');
        }

        if ($path === false) {
            return redirect()->route('admin.products.import.show')
                ->with('error', 'Failed to save the uploaded file. Check storage permissions.');
        }

        $productImport = ProductImport::create([
            'user_id' => auth()->id(),
            'file_path' => $path,
            'original_name' => $file->getClientOriginalName(),
            'status' => ProductImport::STATUS_PENDING,
        ]);

        ProcessProductImportJob::dispatch($productImport);

        return redirect()->route('admin.products.import.reports')
            ->with('success', 'Import started in the background. View the report below. You can leave this page; the import will continue.');
    }

    /**
     * List product import reports (background import history).
     */
    public function importReports(Request $request): View
    {
        $this->authorize('products.view');
        $imports = ProductImport::query()
            ->with('user')
            ->orderByDesc('created_at')
            ->paginate(15);
        return view('admin.products.import-reports', ['imports' => $imports]);
    }

    /**
     * Show a single product import report.
     */
    public function importReportShow(ProductImport $productImport): View
    {
        $this->authorize('products.view');
        $productImport->load('user');
        return view('admin.products.import-report-show', ['import' => $productImport]);
    }

    /**
     * Import a single or service product
     */
    private function importSingleOrServiceProduct(array $row, array $columnMap, int $index, string $productType): array
    {
        try {
            // Get values from CSV
            $name = $row[$columnMap['name']] ?? '';
            $categoryName = $row[$columnMap['category_name']] ?? '';
            $tags = $row[$columnMap['tags']] ?? '';
            $price = $row[$columnMap['price']] ?? '';
            $mrp = $row[$columnMap['mrp']] ?? '';
            $purchase_price = $row[$columnMap['purchase_price']] ?? null;
            $wholesale_price = $row[$columnMap['wholesale_price']] ?? null;
            $openingStock = $row[$columnMap['opening_stock'] ?? $columnMap['stock'] ?? null] ?? 0;
            $barcode = $row[$columnMap['barcode']] ?? '';
            $unitName = $row[$columnMap['unit_name']] ?? '';
            $shortDesc = $row[$columnMap['short_desc']] ?? '';
            $longDesc = $row[$columnMap['long_desc']] ?? '';
            $isActive = $row[$columnMap['is_active']] ?? '1';
            $isFeatured = $row[$columnMap['is_featured']] ?? '0';
            $isPrebooking = $row[$columnMap['is_prebooking']] ?? '0';
            $imageName = $row[$columnMap['image_name']] ?? '';
            
            // Validate required fields
            if (empty($name) || empty($categoryName)) {
                return ['success' => false, 'error' => "Row " . ($index + 2) . ": Missing required fields (name or category_name)"];
            }
            
            // For single products, price is required
            if (empty($price)) {
                return ['success' => false, 'error' => "Row " . ($index + 2) . ": Missing required field (price)"];
            }
            
            // Find category by name
            $category = Category::where('name', $categoryName)->first();
            if (!$category) {
                return ['success' => false, 'error' => "Row " . ($index + 2) . ": Category '{$categoryName}' not found"];
            }
            
            // Find unit by name (optional)
            $unitId = null;
            if (!empty($unitName)) {
                $unit = Unit::where('name', $unitName)->first();
                if ($unit) {
                    $unitId = $unit->id;
                }
            }
            
            // Validate price
            if (!empty($price) && (!is_numeric($price) || $price < 0)) {
                return ['success' => false, 'error' => "Row " . ($index + 2) . ": Invalid price '{$price}'"];
            }
            
            // Validate MRP if provided
            if (!empty($mrp) && (!is_numeric($mrp) || $mrp < 0)) {
                return ['success' => false, 'error' => "Row " . ($index + 2) . ": Invalid MRP '{$mrp}'"];
            }
            
            // Validate stock (for single products)
            if ($productType === 'single') {
                $openingStock = (int)$openingStock;
                if ($openingStock < 0) {
                    $openingStock = 0;
                }
            }

            if (!empty($barcode)) {
                if (Product::where('barcode', $barcode)->exists()) {
                    $barcode = null;
                }
            }

            if(empty($barcode)){
                $barcode = $this->generateBarcode(Product::class);
            }
            
            // Parse boolean fields
            $isActive = in_array(strtolower($isActive), ['1', 'true', 'yes', 'active']);
            $isFeatured = in_array(strtolower($isFeatured), ['1', 'true', 'yes', 'featured']);
            $isPrebooking = in_array(strtolower($isPrebooking), ['1', 'true', 'yes', 'prebooking']);
            
            // Generate slug from name
            $slug = \Illuminate\Support\Str::slug($name);
            $originalSlug = $slug;
            $counter = 1;
            while (Product::where('slug', $slug)->exists()) {
                $slug = $originalSlug . '-' . $counter;
                $counter++;
            }

            // Generate SKU if not provided
            $sku = '';
            if (isset($columnMap['sku']) && !empty($row[$columnMap['sku']])) {
                $sku = trim($row[$columnMap['sku']]);
                // Validate SKU uniqueness
                if (Product::where('sku', $sku)->exists()) {
                    $sku = ''; // Reset if not unique
                }
            }
            
            if (empty($sku)) {
                // Auto-generate SKU
                do {
                    $sku = strtoupper(substr(preg_replace('/[^a-zA-Z0-9]/', '', $name), 0, 10)) . '-' . time() . '-' . rand(100, 999);
                } while (Product::where('sku', $sku)->exists());
            }
            
            // Create product (image set after create so we have product id for folder)
            $productData = [
                'category_id' => $category->id,
                'unit_id' => $unitId,
                'product_type' => $productType,
                'parent_id' => null, // Single products have no parent
                'name' => $name,
                'slug' => $slug,
                'sku' => $sku,
                'tags' => $tags,
                'price' => $price,
                'mrp' => !empty($mrp) ? $mrp : null,
                'purchase_price' => $purchase_price,
                'wholesale_price' => $wholesale_price,
                'opening_stock' => $openingStock,
                'barcode' => $barcode,
                'current_stock' => $openingStock,
                'short_desc' => $shortDesc,
                'long_desc' => $longDesc,
                'image_path' => null,
                'image' => null,
                'is_active' => $isActive,
                'is_featured' => $isFeatured,
                'is_prebooking' => $isPrebooking,
            ];

            $product = Product::create($productData);

            // Handle image import: same pipeline as manual upload (variants + image JSON)
            if (!empty($imageName)) {
                $imageNames = array_map('trim', explode(',', $imageName));
                $firstImageName = $imageNames[0];
                $importImagePath = public_path('uploads/imports/products/' . $firstImageName);
                $allowedExtensions = ['jpg', 'jpeg', 'png', 'webp'];
                $maxSizeBytes = 5 * 1024 * 1024; // 5MB
                if (file_exists($importImagePath)) {
                    $ext = strtolower(pathinfo($firstImageName, PATHINFO_EXTENSION));
                    $size = filesize($importImagePath);
                    if (in_array($ext, $allowedExtensions) && $size > 0 && $size <= $maxSizeBytes) {
                        $mimeType = mime_content_type($importImagePath) ?: 'image/jpeg';
                        $uploadedFile = new \Illuminate\Http\UploadedFile($importImagePath, $firstImageName, $mimeType, 0, true);
                        $imageResult = $this->imageService->processProductImageVariants($uploadedFile, $product->id);
                        $product->update([
                            'image_path' => $imageResult['original'],
                            'image' => $imageResult,
                        ]);
                    }
                }
            }

            // Create initial stock movement if opening stock > 0 (for single products)
            if ($productType === 'single' && $openingStock > 0) {
                \App\Models\StockMovement::create([
                    'product_id' => $product->id,
                    'type' => \App\Models\StockMovement::TYPE_OPENING_STOCK,
                    'quantity' => $openingStock,
                    'notes' => 'Opening stock',
                    'created_by' => auth()->check() ? auth()->id() : 1,
                ]);
                $product->updateCurrentStock();
            }

            return ['success' => true];
        } catch (\Exception $e) {
            return ['success' => false, 'error' => "Row " . ($index + 2) . ": " . $e->getMessage()];
        }
    }

    /**
     * Import a variant product with its variants
     */
    private function importVariantProduct(array $variantRows, array $columnMap): array
    {
        try {
            if (empty($variantRows)) {
                return ['success' => false, 'error' => 'No variant rows provided'];
            }
            
            // Use first row for product-level data
            $firstRow = $variantRows[0]['row'];
            $firstIndex = $variantRows[0]['index'];
            
            $name = $firstRow[$columnMap['name']] ?? '';
            $categoryName = $firstRow[$columnMap['category_name']] ?? '';
            $tags = $firstRow[$columnMap['tags']] ?? '';
            $price = $firstRow[$columnMap['price']] ?? '0';
            $mrp = $firstRow[$columnMap['mrp']] ?? '';
            $purchase_price = $firstRow[$columnMap['purchase_price']] ?? '0';
            $wholesale_price = $firstRow[$columnMap['wholesale_price']] ?? '0';
            $barcode = $firstRow[$columnMap['barcode']] ?? '';
            $unitName = $firstRow[$columnMap['unit_name']] ?? '';
            $shortDesc = $firstRow[$columnMap['short_desc']] ?? '';
            $longDesc = $firstRow[$columnMap['long_desc']] ?? '';
            $isActive = $firstRow[$columnMap['is_active']] ?? '1';
            $isFeatured = $firstRow[$columnMap['is_featured']] ?? '0';
            $isPrebooking = $firstRow[$columnMap['is_prebooking']] ?? '0';
            $imageName = $firstRow[$columnMap['image_name']] ?? '';
            
            // Validate required fields
            if (empty($name) || empty($categoryName)) {
                return ['success' => false, 'error' => "Row " . ($firstIndex + 2) . ": Missing required fields (name or category_name)"];
            }
            
            // Find category by name
            $category = Category::where('name', $categoryName)->first();
            if (!$category) {
                return ['success' => false, 'error' => "Row " . ($firstIndex + 2) . ": Category '{$categoryName}' not found"];
            }
            
            // Find unit by name (optional)
            $unitId = null;
            if (!empty($unitName)) {
                $unit = Unit::where('name', $unitName)->first();
                if ($unit) {
                    $unitId = $unit->id;
                }
            }

            if (!empty($barcode)) {
                if (Product::where('barcode', $barcode)->exists()) {
                    $barcode = null;
                }
            }
            
            if(empty($barcode)){
                $barcode = $this->generateBarcode(Product::class);
            }
            // Parse boolean fields
            $isActive = in_array(strtolower($isActive), ['1', 'true', 'yes', 'active']);
            $isFeatured = in_array(strtolower($isFeatured), ['1', 'true', 'yes', 'featured']);
            $isPrebooking = in_array(strtolower($isPrebooking), ['1', 'true', 'yes', 'prebooking']);
            
            // Generate slug from name
            $slug = \Illuminate\Support\Str::slug($name);
            $originalSlug = $slug;
            $counter = 1;
            while (Product::where('slug', $slug)->exists()) {
                $slug = $originalSlug . '-' . $counter;
                $counter++;
            }

            // Generate SKU for parent variant product if not provided
            $sku = '';
            if (isset($columnMap['sku']) && !empty($firstRow[$columnMap['sku']])) {
                $sku = trim($firstRow[$columnMap['sku']]);
                // Validate SKU uniqueness
                if (Product::where('sku', $sku)->exists()) {
                    $sku = ''; // Reset if not unique
                }
            }
            
            if (empty($sku)) {
                // Auto-generate SKU for parent
                do {
                    $sku = strtoupper(substr(preg_replace('/[^a-zA-Z0-9]/', '', $name), 0, 10)) . '-PARENT-' . time();
                } while (Product::where('sku', $sku)->exists());
            }
            
            // Create parent variant product (image set after create so we have product id for folder)
            $productData = [
                'category_id' => $category->id,
                'unit_id' => $unitId,
                'product_type' => 'variant',
                'parent_id' => null, // Parent variant products have no parent
                'name' => $name,
                'slug' => $slug,
                'sku' => $sku,
                'tags' => $tags,
                'price' => !empty($price) ? $price : 0,
                'mrp' => !empty($mrp) ? $mrp : null,
                'purchase_price' => !empty($purchase_price) ? $purchase_price : 0,
                'wholesale_price' => !empty($wholesale_price) ? $wholesale_price : 0,
                'opening_stock' => 0, // Variant parent products have 0 at product level
                'current_stock' => 0,
                'barcode' => $barcode,
                'short_desc' => $shortDesc,
                'long_desc' => $longDesc,
                'image_path' => null,
                'image' => null,
                'is_active' => $isActive,
                'is_featured' => $isFeatured,
                'is_prebooking' => $isPrebooking,
            ];

            $product = Product::create($productData);

            // Handle parent image import: same pipeline as manual upload (variants + image JSON)
            if (!empty($imageName)) {
                $imageNames = array_map('trim', explode(',', $imageName));
                $firstImageName = $imageNames[0];
                $importImagePath = public_path('uploads/imports/products/' . $firstImageName);
                $allowedExtensions = ['jpg', 'jpeg', 'png', 'webp'];
                $maxSizeBytes = 5 * 1024 * 1024; // 5MB
                if (file_exists($importImagePath)) {
                    $ext = strtolower(pathinfo($firstImageName, PATHINFO_EXTENSION));
                    $size = filesize($importImagePath);
                    if (in_array($ext, $allowedExtensions) && $size > 0 && $size <= $maxSizeBytes) {
                        $mimeType = mime_content_type($importImagePath) ?: 'image/jpeg';
                        $uploadedFile = new \Illuminate\Http\UploadedFile($importImagePath, $firstImageName, $mimeType, 0, true);
                        $imageResult = $this->imageService->processProductImageVariants($uploadedFile, $product->id);
                        $product->update([
                            'image_path' => $imageResult['original'],
                            'image' => $imageResult,
                        ]);
                    }
                }
            }

            $variantsCreated = 0;

            // Create variants
            foreach ($variantRows as $variantItem) {
                $row = $variantItem['row'];
                $index = $variantItem['index'];
                
                $variantAttributes = $row[$columnMap['variant_attributes']] ?? '';
                $variantSku = $row[$columnMap['variant_sku']] ?? '';
                $variantPrice = $row[$columnMap['variant_price']] ?? '';
                $variantMrp = $row[$columnMap['variant_mrp']] ?? '';
                $variantPurchasePrice = $row[$columnMap['variant_purchase_price']] ?? '';
                $variantWholesalePrice = $row[$columnMap['variant_wholesale_price']] ?? '';
                $variantOpeningStock = $row[$columnMap['variant_opening_stock']] ?? 0;
                $variantBarcode = $row[$columnMap['variant_barcode']] ?? '';
                $variantImageName = $row[$columnMap['variant_image_name']] ?? '';
                
                // Validate variant attributes
                if (empty($variantAttributes)) {
                    continue; // Skip variant if no attributes
                }
                
                // Match attribute values
                $attributeValueIds = $this->matchAttributeValues($variantAttributes);
                if (empty($attributeValueIds)) {
                    continue; // Skip variant if no matching attributes
                }
                
                // Auto-generate SKU if not provided
                if (empty($variantSku) || trim($variantSku) === '') {
                    do {
                        $variantSku = 'VAR-' . $product->id . '-' . time() . '-' . rand(1000, 9999);
                    } while (Product::where('sku', $variantSku)->exists());
                }
                
                // Validate variant price (use product price as fallback)
                $finalVariantPrice = !empty($variantPrice) && is_numeric($variantPrice) ? $variantPrice : $product->price;
                if ($finalVariantPrice < 0) {
                    $finalVariantPrice = 0;
                }
                
                // Validate variant MRP
                $finalVariantMrp = null;
                if (!empty($variantMrp) && is_numeric($variantMrp) && $variantMrp >= 0) {
                    $finalVariantMrp = $variantMrp;
                } elseif (!empty($product->mrp)) {
                    $finalVariantMrp = $product->mrp;
                }

                $finalvariantPurchasePrice = null;
                if (!empty($variantPurchasePrice) && is_numeric($variantPurchasePrice) && $variantPurchasePrice >= 0) {
                    $finalvariantPurchasePrice = $variantPurchasePrice;
                } elseif (!empty($product->purchase_price)) {
                    $finalvariantPurchasePrice = $product->purchase_price;
                }

                $finalvariantWholesalePrice = null;
                if (!empty($variantWholesalePrice) && is_numeric($variantWholesalePrice) && $variantWholesalePrice >= 0) {
                    $finalvariantWholesalePrice = $variantWholesalePrice;
                } elseif (!empty($product->wholesale_price)) {
                    $finalvariantWholesalePrice = $product->wholesale_price;
                }

                if (!empty($variantBarcode)) {
                    if (Product::where('barcode', $variantBarcode)->exists()) {
                        $variantBarcode = null;
                    }
                }

                if(empty($variantBarcode)){
                    $variantBarcode = $this->generateBarcode(Product::class);
                }
                // Validate variant stock
                $variantOpeningStock = (int)$variantOpeningStock;
                if ($variantOpeningStock < 0) {
                    $variantOpeningStock = 0;
                }

                // Generate variant name from attribute values
                $attributeValues = AttributeValue::whereIn('id', $attributeValueIds)
                    ->with('attribute')
                    ->get();
                $variationName = $attributeValues->map(function($av) {
                    return $av->attribute->name . ': ' . $av->value;
                })->implode(' - ');
                
                // Generate slug for variant
                $slug = \Illuminate\Support\Str::slug($product->name . ' ' . $variationName);
                $originalSlug = $slug;
                $counter = 1;
                while (Product::where('slug', $slug)->exists()) {
                    $slug = $originalSlug . '-' . $counter;
                    $counter++;
                }
                
                // Create variant as Product (image set after create: own image or parent fallback)
                $variantData = [
                    'parent_id' => $product->id,
                    'product_type' => 'variant',
                    'category_id' => $product->category_id,
                    'unit_id' => $product->unit_id,
                    'tax_id' => $product->tax_id,
                    'tax_rate_snapshot' => $product->tax_rate_snapshot,
                    'brand_id' => $product->brand_id,
                    'name' => $product->name . ' - ' . $variationName,
                    'slug' => $slug,
                    'sku' => $variantSku,
                    'price' => $finalVariantPrice,
                    'mrp' => $finalVariantMrp,
                    'purchase_price' => $finalvariantPurchasePrice,
                    'wholesale_price' => $finalvariantWholesalePrice,
                    'opening_stock' => $variantOpeningStock,
                    'current_stock' => $variantOpeningStock,
                    'barcode' => !empty($variantBarcode) ? $variantBarcode : null,
                    'hsn_code' => $product->hsn_code,
                    'image_path' => null,
                    'image' => null,
                    'short_desc' => $product->short_desc,
                    'long_desc' => $product->long_desc,
                    'is_active' => true,
                    'is_featured' => false,
                    'is_prebooking' => $product->is_prebooking,
                ];

                $variant = Product::create($variantData);

                // Handle variant image: same pipeline as manual upload, or fallback to parent image
                $variantImageProcessed = false;
                if (!empty($variantImageName)) {
                    $importImagePath = public_path('uploads/imports/products/' . $variantImageName);
                    $allowedExtensions = ['jpg', 'jpeg', 'png', 'webp'];
                    $maxSizeBytes = 5 * 1024 * 1024; // 5MB
                    if (file_exists($importImagePath)) {
                        $ext = strtolower(pathinfo($variantImageName, PATHINFO_EXTENSION));
                        $size = filesize($importImagePath);
                        if (in_array($ext, $allowedExtensions) && $size > 0 && $size <= $maxSizeBytes) {
                            $mimeType = mime_content_type($importImagePath) ?: 'image/jpeg';
                            $uploadedFile = new \Illuminate\Http\UploadedFile($importImagePath, $variantImageName, $mimeType, 0, true);
                            $imageResult = $this->imageService->processProductImageVariants($uploadedFile, $variant->id);
                            $variant->update([
                                'image_path' => $imageResult['original'],
                                'image' => $imageResult,
                            ]);
                            $variantImageProcessed = true;
                        }
                    }
                }
                if (!$variantImageProcessed) {
                    $variant->update([
                        'image_path' => $product->image_path,
                        'image' => $product->image,
                    ]);
                }

                // Attach attribute values
                $variant->attributeValues()->attach($attributeValueIds);
                
                // Create opening stock movement
                if ($variantOpeningStock > 0) {
                    \App\Models\VariantStockMovement::create([
                        'product_id' => $variant->id,
                        'type' => \App\Models\VariantStockMovement::TYPE_OPENING_STOCK,
                        'quantity' => $variantOpeningStock,
                        'notes' => 'Opening stock',
                        'created_by' => auth()->check() ? auth()->id() : 1,
                    ]);
                    $variant->updateCurrentStock();
                }
                
                $variantsCreated++;
            }
            
            if ($variantsCreated === 0) {
                // Delete product if no variants were created
                $product->delete();
                return ['success' => false, 'error' => "Product '{$name}': No valid variants created. Check variant_attributes column."];
            }
            
            return ['success' => true, 'variants_created' => $variantsCreated];
        } catch (\Exception $e) {
            return ['success' => false, 'error' => 'Variant product import failed: ' . $e->getMessage()];
        }
    }

    /**
     * Match comma-separated attribute values to AttributeValue records
     */
    private function matchAttributeValues(string $variantAttributes): array
    {
        if (empty($variantAttributes)) {
            return [];
        }
        
        // Split by comma and trim
        $values = array_map('trim', explode(',', $variantAttributes));
        $attributeValueIds = [];
        
        foreach ($values as $value) {
            if (empty($value)) {
                continue;
            }
            
            // Search for matching attribute value (case-insensitive)
            $attributeValue = AttributeValue::where('status', 'active')
                ->whereRaw('LOWER(value) = ?', [strtolower($value)])
                ->first();
            
            if ($attributeValue) {
                $attributeValueIds[] = $attributeValue->id;
            }
        }
        
        return $attributeValueIds;
    }

    // Purchase Price Management Methods

    /**
     * Bulk update purchase prices
     */
    public function bulkUpdate(Request $request)
    {
        $request->validate([
            'products' => 'required|array',
            'products.*.id' => 'required|exists:products,id',
            'products.*.purchase_price' => ['required', 'numeric', $this->decimalRangeRule(0, 999999.99)],
        ]);

        DB::beginTransaction();
        try {
            foreach ($request->products as $productData) {
                Product::where('id', $productData['id'])
                    ->update(['purchase_price' => $productData['purchase_price']]);
            }
            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Purchase prices updated successfully.'
            ]);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'success' => false,
                'message' => 'Failed to update purchase prices: ' . $e->getMessage()
            ], 500);
        }
    }

    /**
     * Export products with purchase prices to CSV
     */
    public function exportCsv(Request $request): StreamedResponse
    {
        $query = Product::with('category');

        // Apply same filters as index
        if ($request->filled('category_id')) {
            $query->where('category_id', $request->category_id);
        }

        if ($request->filled('purchase_price_status')) {
            if ($request->purchase_price_status === 'missing') {
                $query->missingPurchasePrice();
            } elseif ($request->purchase_price_status === 'has_price') {
                $query->withPurchasePrice();
            }
        }

        if ($request->filled('search')) {
            $search = $request->search;
            $query->where(function ($q) use ($search) {
                $q->where('name', 'like', "%{$search}%")
                  ->orWhere('barcode', 'like', "%{$search}%")
                  ->orWhere('slug', 'like', "%{$search}%");
            });
        }

        $products = $query->get();

        $filename = 'products_purchase_prices_' . now()->format('Y-m-d_H-i-s') . '.csv';
        
        $headers = [
            'Content-Type' => 'text/csv',
            'Content-Disposition' => 'attachment; filename="' . $filename . '"',
        ];

        $callback = function() use ($products) {
            $file = fopen('php://output', 'w');
            
            // CSV Headers
            fputcsv($file, [
                'ID',
                'Name',
                'Barcode',
                'Category',
                'Current Price',
                'Purchase Price',
                'MRP',
                'Current Stock',
                'Status'
            ]);

            foreach ($products as $product) {
                fputcsv($file, [
                    $product->id,
                    $product->name,
                    $product->barcode ?? $product->slug,
                    $product->category->name ?? '',
                    $product->price,
                    $product->purchase_price ?? '',
                    $product->mrp ?? '',
                    $product->current_stock,
                    $product->is_active ? 'Active' : 'Inactive'
                ]);
            }
            
            fclose($file);
        };

        return response()->stream($callback, 200, $headers);
    }

    /**
     * Show CSV import form for purchase prices
     */
    public function importForm(): View
    {
        return view('admin.products.import');
    }

    /**
     * Import purchase prices from CSV
     */
    public function importCsv(Request $request)
    {
        $request->validate([
            'csv_file' => 'required|file|mimes:csv,txt|max:2048',
            'update_existing' => 'boolean',
        ]);

        $file = $request->file('csv_file');
        $updateExisting = $request->boolean('update_existing', false);

        try {
            $csvData = array_map('str_getcsv', file($file->getPathname()));
            $headers = array_shift($csvData); // Remove header row

            // Validate CSV headers
            $requiredHeaders = ['id', 'purchase_price'];
            $headerMap = [];
            
            foreach ($requiredHeaders as $required) {
                $headerIndex = array_search(strtolower($required), array_map('strtolower', $headers));
                if ($headerIndex === false) {
                    return back()->withErrors(['csv_file' => "Missing required column: {$required}"]);
                }
                $headerMap[$required] = $headerIndex;
            }

            $updated = 0;
            $errors = [];
            $skipped = 0;

            DB::beginTransaction();

            foreach ($csvData as $rowIndex => $row) {
                $rowNumber = $rowIndex + 2; // +2 because we removed header and arrays are 0-indexed
                
                if (empty($row) || count($row) < count($requiredHeaders)) {
                    continue;
                }

                $productId = trim($row[$headerMap['id']]);
                $purchasePrice = trim($row[$headerMap['purchase_price']]);

                // Validate data
                if (empty($productId) || !is_numeric($productId)) {
                    $errors[] = "Row {$rowNumber}: Invalid product ID";
                    continue;
                }

                if (empty($purchasePrice) || !is_numeric($purchasePrice) || $purchasePrice < 0) {
                    $errors[] = "Row {$rowNumber}: Invalid purchase price";
                    continue;
                }

                // Find product
                $product = Product::find($productId);
                if (!$product) {
                    $errors[] = "Row {$rowNumber}: Product not found (ID: {$productId})";
                    continue;
                }

                // Check if should update existing
                if (!$updateExisting && $product->hasPurchasePrice()) {
                    $skipped++;
                    continue;
                }

                // Update purchase price
                $product->update(['purchase_price' => $purchasePrice]);
                $updated++;
            }

            if (!empty($errors) && count($errors) > 10) {
                DB::rollBack();
                return back()->withErrors(['csv_file' => 'Too many errors in CSV file. Please check your data.']);
            }

            DB::commit();

            $message = "Import completed. Updated: {$updated} products";
            if ($skipped > 0) {
                $message .= ", Skipped: {$skipped} products (already have purchase price)";
            }
            if (!empty($errors)) {
                $message .= ". Errors: " . implode(', ', array_slice($errors, 0, 5));
                if (count($errors) > 5) {
                    $message .= " and " . (count($errors) - 5) . " more...";
                }
            }

            return back()->with('success', $message);

        } catch (\Exception $e) {
            DB::rollBack();
            return back()->withErrors(['csv_file' => 'Import failed: ' . $e->getMessage()]);
        }
    }

    /**
     * Download CSV template for purchase price import
     */
    public function downloadTemplate(): StreamedResponse
    {
        $filename = 'purchase_price_import_template.csv';
        
        $headers = [
            'Content-Type' => 'text/csv',
            'Content-Disposition' => 'attachment; filename="' . $filename . '"',
        ];

        $callback = function() {
            $file = fopen('php://output', 'w');
            
            // CSV Headers with sample data
            fputcsv($file, ['id', 'purchase_price', 'notes']);
            fputcsv($file, ['1', '45.50', 'Sample product purchase price']);
            fputcsv($file, ['2', '120.00', 'Another sample']);
            
            fclose($file);
        };

        return response()->stream($callback, 200, $headers);
    }

    // ==================== Variant Product Methods ====================

    /**
     * Show the form for creating a variant product
     */
    public function createVariant(): View
    {
        $categories = Category::where('is_active', 1)->get();
        $units = Unit::all();
        $brands = Brand::all();
        $taxes = Tax::where('is_active', 1)->get();
        $attributes = Attribute::with('activeValues')->active()->get();

        return view('admin.products.create-variant', compact('categories', 'units', 'brands', 'taxes', 'attributes'));
    }

    /**
     * Store a newly created variant product with all variants
     */
    public function storeVariant(Request $request): RedirectResponse
    {
        $request->validate([
            'category_id' => 'required|exists:categories,id',
            'unit_id' => 'nullable|exists:units,id',
            'tax_id' => 'nullable|exists:taxes,id',
            'brand_id' => 'nullable|exists:brands,id',
            'name' => ['required', 'string', $this->maxLengthRule(255)],
            'slug' => ['nullable', 'string', $this->maxLengthRule(191), 'unique:products'],
            'barcode' => ['nullable', 'string', $this->maxLengthRule(8), 'unique:products'],
            'tags' => 'nullable|string',
            'shipping_days' => ['nullable', 'integer', $this->integerRangeRule(0)],
            'short_desc' => 'nullable|string',
            'long_desc' => 'nullable|string',
            'image' => 'nullable|image|mimes:jpeg,png,jpg,gif,webp|max:5120',
            'is_active' => 'boolean',
            'is_verified' => 'boolean',
            'channel_visibility' => ['required', 'string', \Illuminate\Validation\Rule::in(\App\Models\Product::CHANNEL_VISIBILITIES)],
            'is_featured' => 'boolean',
            'is_prebooking' => 'boolean',
            'variants' => ['required', 'array', $this->arrayMinCountRule(1)],
            'variants.*.attribute_value_ids' => ['required', 'array', $this->arrayMinCountRule(1)],
            'variants.*.attribute_value_ids.*' => 'exists:attribute_values,id',
            'variants.*.sku' => ['required', 'string', $this->maxLengthRule(191)],
            'variants.*.price' => ['required', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'variants.*.mrp' => ['nullable', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'variants.*.purchase_price' => ['nullable', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'variants.*.wholesale_price' => ['nullable', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'variants.*.opening_stock' => ['required', 'integer', $this->integerRangeRule(0)],
            'variants.*.shipping_days' => ['nullable', 'integer', $this->integerRangeRule(0)],
            'variants.*.barcode' => ['nullable', 'string', $this->maxLengthRule(191)],
            'variants.*.image' => 'nullable|image|mimes:jpeg,png,jpg,gif,webp|max:5120',
        ]);

        DB::beginTransaction();
        try {
            $data = $request->all();
            $data['channel_visibility'] = $request->input('channel_visibility', Product::CHANNEL_BOTH);
            $data['product_type'] = 'variant';
            
            // Auto-generate slug if not provided
            if (empty($data['slug'])) {
                $data['slug'] = \Illuminate\Support\Str::slug($data['name']);
                $originalSlug = $data['slug'];
                $counter = 1;
                while (Product::where('slug', $data['slug'])->exists()) {
                    $data['slug'] = $originalSlug . '-' . $counter;
                    $counter++;
                }
            }

            if(empty($data['barcode'])){
                $data['barcode'] = $this->generateBarcode(Product::class);
            }

            // Handle tax rate snapshot
            if ($request->filled('tax_id')) {
                $tax = Tax::find($request->tax_id);
                if ($tax) {
                    $data['tax_rate_snapshot'] = $tax->rate;
                }
            }

            // Set default values for variant parent products
            $data['price'] = 0; // Will be set by variants
            $data['current_stock'] = 0; // Will be calculated from variants
            $data['opening_stock'] = 0;

            // Create parent product
            $product = Product::create($data);

            // Handle parent image upload (after create so we have product id)
            if ($request->hasFile('image')) {
                $imageResult = $this->imageService->processProductImageVariants($request->file('image'), $product->id);
                $product->update([
                    'image_path' => $imageResult['original'],
                    'image' => $imageResult,
                ]);
            }

            // Create all variants
            $variantsCreated = 0;
            foreach ($request->variants as $index => $variantData) {
                // Get attribute values for variant name
                $attributeValues = AttributeValue::whereIn('id', $variantData['attribute_value_ids'])
                    ->with('attribute')
                    ->get();
                $variationName = $attributeValues->map(function($av) {
                    return $av->attribute->name . ': ' . $av->value;
                })->implode(' - ');
                
                // Generate slug for variant
                $slug = \Illuminate\Support\Str::slug($product->name . ' ' . $variationName);
                $originalSlug = $slug;
                $counter = 1;
                while (Product::where('slug', $slug)->exists()) {
                    $slug = $originalSlug . '-' . $counter;
                    $counter++;
                }

                // Validate SKU uniqueness
                $sku = $variantData['sku'];
                $skuCounter = 1;
                $originalSku = $sku;
                while (Product::where('sku', $sku)->exists()) {
                    $sku = $originalSku . '-' . $skuCounter;
                    $skuCounter++;
                }

                // Generate barcode if not provided
                $barcode = $variantData['barcode'] ?? null;
                if (empty($barcode)) {
                    $barcode = $this->generateBarcode(Product::class);
                }

                // Create variant as Product (image set after create if uploaded)
                $variant = Product::create([
                    'parent_id' => $product->id,
                    'product_type' => 'variant',
                    'category_id' => $product->category_id,
                    'unit_id' => $product->unit_id,
                    'tax_id' => $product->tax_id,
                    'tax_rate_snapshot' => $product->tax_rate_snapshot,
                    'brand_id' => $product->brand_id,
                    'name' => $product->name . ' - ' . $variationName,
                    'slug' => $slug,
                    'sku' => $sku,
                    'barcode' => $barcode,
                    'hsn_code' => $product->hsn_code,
                    'shipping_days' => $variantData['shipping_days'] ?? $product->shipping_days,
                    'price' => $variantData['price'],
                    'mrp' => $variantData['mrp'] ?? null,
                    'purchase_price' => $variantData['purchase_price'] ?? null,
                    'wholesale_price' => $variantData['wholesale_price'] ?? null,
                    'opening_stock' => $variantData['opening_stock'] ?? 0,
                    'current_stock' => $variantData['opening_stock'] ?? 0,
                    'image_path' => $product->image_path,
                    'short_desc' => $product->short_desc,
                    'long_desc' => $product->long_desc,
                    'tags' => $product->tags ?? $request->input('tags'),
                    'is_active' => true,
                    'is_verified' => $product->is_verified,
                    'channel_visibility' => $product->channel_visibility,
                    'is_featured' => false,
                    'is_prebooking' => $product->is_prebooking,
                ]);

                // Handle variant image upload (folder: products/{variant_id}/)
                if ($request->hasFile("variants.{$index}.image")) {
                    $imageResult = $this->imageService->processProductImageVariants($request->file("variants.{$index}.image"), $variant->id);
                    $variant->update([
                        'image_path' => $imageResult['original'],
                        'image' => $imageResult,
                    ]);
                }

                // Attach attribute values
                $variant->attributeValues()->attach($variantData['attribute_value_ids']);

                // Create opening stock movement
                if ($variant->opening_stock > 0) {
                    VariantStockMovement::create([
                        'product_id' => $variant->id,
                        'type' => VariantStockMovement::TYPE_OPENING_STOCK,
                        'quantity' => $variant->opening_stock,
                        'notes' => 'Opening stock',
                        'created_by' => auth()->check() ? auth()->id() : 1,
                    ]);
                    $variant->updateCurrentStock();
                }

                $variantsCreated++;
            }

            DB::commit();

            return redirect()->route('admin.products.variants.index', $product->id)
                ->with('success', "Variant product created successfully with {$variantsCreated} variant(s).");
        } catch (\Exception $e) {
            DB::rollBack();
            return back()->withErrors(['error' => 'Failed to create variant product: ' . $e->getMessage()])->withInput();
        }
    }

    /**
     * Show the form for editing a variant product
     */
    public function editVariant(Product $product)
    {
        if ($product->product_type !== 'variant') {
            return redirect()->route('admin.products.index')
                ->with('error', 'This is not a variant product.');
        }

        $categories = Category::where('is_active', 1)->get();
        $units = Unit::all();
        $brands = Brand::all();
        $taxes = Tax::where('is_active', 1)->get();
        $attributes = Attribute::with('activeValues')->active()->get();
        $variants = $product->variants()->with('attributeValues.attribute')->get();
        $product->load('media');

        return view('admin.products.edit-variant', compact('product', 'categories', 'units', 'brands', 'taxes', 'attributes', 'variants'));
    }

    /**
     * Update a variant product
     */
    public function updateVariant(Request $request, Product $product): RedirectResponse
    {
        if ($product->product_type !== 'variant') {
            return redirect()->route('admin.products.index')
                ->with('error', 'This is not a variant product.');
        }

        $request->validate([
            'category_id' => 'required|exists:categories,id',
            'unit_id' => 'nullable|exists:units,id',
            'tax_id' => 'nullable|exists:taxes,id',
            'brand_id' => 'nullable|exists:brands,id',
            'name' => ['required', 'string', $this->maxLengthRule(255)],
            'slug' => ['nullable', 'string', $this->maxLengthRule(191), 'unique:products,slug,' . $product->id],
            'tags' => 'nullable|string',
            'shipping_days' => ['nullable', 'integer', $this->integerRangeRule(0)],
            'short_desc' => 'nullable|string',
            'long_desc' => 'nullable|string',
            'image' => 'nullable|image|mimes:jpeg,png,jpg,gif,webp|max:5120',
            'is_active' => 'boolean',
            'is_verified' => 'boolean',
            'channel_visibility' => ['required', 'string', \Illuminate\Validation\Rule::in(\App\Models\Product::CHANNEL_VISIBILITIES)],
            'is_featured' => 'boolean',
            'is_prebooking' => 'boolean',
            // Existing variants
            'variants' => 'nullable|array',
            'variants.*.sku' => ['required', 'string', $this->maxLengthRule(191)],
            'variants.*.price' => ['required', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'variants.*.mrp' => ['nullable', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'variants.*.purchase_price' => ['nullable', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'variants.*.wholesale_price' => ['nullable', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'variants.*.barcode' => ['nullable', 'string', $this->maxLengthRule(191)],
            'variants.*.shipping_days' => ['nullable', 'integer', $this->integerRangeRule(0)],
            'variants.*.image' => 'nullable|image|mimes:jpeg,png,jpg,gif,webp|max:5120',
            'variants.*.attribute_value_ids' => ['required', 'array', $this->arrayMinCountRule(1)],
            'variants.*.attribute_value_ids.*' => 'exists:attribute_values,id',
            'delete_variants' => 'nullable|array',
            'delete_variants.*' => 'exists:products,id',
            // New variants
            'new_variants' => 'nullable|array',
            'new_variants.*.sku' => ['required', 'string', $this->maxLengthRule(191), 'unique:products,sku'],
            'new_variants.*.price' => ['required', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'new_variants.*.mrp' => ['nullable', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'new_variants.*.purchase_price' => ['nullable', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'new_variants.*.wholesale_price' => ['nullable', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'new_variants.*.opening_stock' => ['required', 'integer', $this->integerRangeRule(0)],
            'new_variants.*.barcode' => ['nullable', 'string', $this->maxLengthRule(191)],
            'new_variants.*.shipping_days' => ['nullable', 'integer', $this->integerRangeRule(0)],
            'new_variants.*.image' => 'nullable|image|mimes:jpeg,png,jpg,gif,webp|max:5120',
            'new_variants.*.attribute_value_ids' => ['required', 'array', $this->arrayMinCountRule(1)],
            'new_variants.*.attribute_value_ids.*' => 'exists:attribute_values,id',
        ]);

        $data = $request->all();
        $data['channel_visibility'] = $request->input('channel_visibility', $product->channel_visibility ?? Product::CHANNEL_BOTH);
        // Only pass fillable attributes to update (keeps tags and avoids overwriting with null)
        $data = array_intersect_key($data, array_flip($product->getFillable()));
        $data['tags'] = $request->input('tags') ?? $product->tags;
        
        // Auto-generate slug if name changed
        if (empty($data['slug']) || $data['name'] !== $product->name) {
            $newSlug = \Illuminate\Support\Str::slug($data['name']);
            if ($data['name'] !== $product->name) {
                $originalSlug = $newSlug;
                $counter = 1;
                while (Product::where('slug', $newSlug)->where('id', '!=', $product->id)->exists()) {
                    $newSlug = $originalSlug . '-' . $counter;
                    $counter++;
                }
                $data['slug'] = $newSlug;
            } else {
                $data['slug'] = $product->slug;
            }
        }

        // Handle image upload
        if ($request->hasFile('image')) {
            $this->imageService->deleteProductImageFolder($product->id, $product->image_path);
            $imageResult = $this->imageService->processProductImageVariants($request->file('image'), $product->id);
            $data['image_path'] = $imageResult['original'];
            $data['image'] = $imageResult;
        }

        // Handle tax rate snapshot
        if ($request->filled('tax_id')) {
            $tax = Tax::find($request->tax_id);
            if ($tax) {
                $data['tax_rate_snapshot'] = $tax->rate;
            }
        }

        $product->update($data);

        // Handle existing media deletion
        $deleteMediaIds = $request->input('delete_media', []);
        $existingImageIds = $request->input('existing_images', []);
        $existingVideoIds = $request->input('existing_videos', []);
        
        if (!empty($deleteMediaIds)) {
            $product->media()->whereIn('id', $deleteMediaIds)->get()->each(function ($media) {
                Storage::disk('public')->delete($media->file_path);
                $media->delete();
            });
        }
        
        $allCurrentImageIds = $product->media()->images()->pluck('id')->toArray();
        $allCurrentVideoIds = $product->media()->videos()->pluck('id')->toArray();
        
        if ($request->has('existing_images')) {
            $imagesToDelete = array_diff($allCurrentImageIds, $existingImageIds);
            if (!empty($imagesToDelete)) {
                $product->media()->images()->whereIn('id', $imagesToDelete)->get()->each(function ($media) {
                    Storage::disk('public')->delete($media->file_path);
                    $media->delete();
                });
            }
        }
        
        if ($request->has('existing_videos')) {
            $videosToDelete = array_diff($allCurrentVideoIds, $existingVideoIds);
            if (!empty($videosToDelete)) {
                $product->media()->videos()->whereIn('id', $videosToDelete)->get()->each(function ($media) {
                    Storage::disk('public')->delete($media->file_path);
                    $media->delete();
                });
            }
        }

        // Handle new additional images upload
        if ($request->hasFile('additional_images')) {
            $maxDisplayOrder = $product->media()->images()->max('display_order') ?? -1;
            $displayOrder = $maxDisplayOrder + 1;
            foreach ($request->file('additional_images') as $image) {
                $path = $image->store("products/media/images/{$product->id}", 'public');
                ProductMedia::create([
                    'product_id' => $product->id,
                    'type' => 'image',
                    'file_path' => $path,
                    'display_order' => $displayOrder++,
                ]);
            }
        }

        // Handle new videos upload
        if ($request->hasFile('videos')) {
            $maxDisplayOrder = $product->media()->videos()->max('display_order') ?? -1;
            $displayOrder = $maxDisplayOrder + 1;
            foreach ($request->file('videos') as $video) {
                $path = $video->store("products/media/videos/{$product->id}", 'public');
                ProductMedia::create([
                    'product_id' => $product->id,
                    'type' => 'video',
                    'file_path' => $path,
                    'display_order' => $displayOrder++,
                ]);
            }
        }

        DB::beginTransaction();
        try {
            // Update parent product
            $product->update($data);
            
            // Handle variant deletions
            $deleteVariantIds = $request->input('delete_variants', []);
            if (!empty($deleteVariantIds)) {
                Product::whereIn('id', $deleteVariantIds)
                    ->where('parent_id', $product->id)
                    ->delete();
            }
            
            // Update existing variants
            if ($request->has('variants')) {
                foreach ($request->variants as $variantId => $variantData) {
                    $variant = Product::find($variantId);
                    if ($variant && $variant->parent_id === $product->id) {
                        // Get attribute values for variant name
                        $attributeValues = AttributeValue::whereIn('id', $variantData['attribute_value_ids'])
                            ->with('attribute')
                            ->get();
                        $variationName = $attributeValues->map(function($av) {
                            return $av->attribute->name . ': ' . $av->value;
                        })->implode(' - ');
                        
                        // Validate SKU uniqueness
                        $sku = $variantData['sku'];
                        if ($sku !== $variant->sku) {
                            $skuCounter = 1;
                            $originalSku = $sku;
                            while (Product::where('sku', $sku)->where('id', '!=', $variant->id)->exists()) {
                                $sku = $originalSku . '-' . $skuCounter;
                                $skuCounter++;
                            }
                        }
                        
                        // Handle variant image upload (folder: products/{variant_id}/)
                        $variantUpdate = [
                            'name' => $product->name . ' - ' . $variationName,
                            'sku' => $sku,
                            'price' => $variantData['price'],
                            'mrp' => $variantData['mrp'] ?? null,
                            'purchase_price' => $variantData['purchase_price'] ?? null,
                            'wholesale_price' => $variantData['wholesale_price'] ?? null,
                            'barcode' => $variantData['barcode'] ?? $variant->barcode,
                            'shipping_days' => $variantData['shipping_days'] ?? $product->shipping_days,
                            'tags' => $product->tags ?? $request->input('tags'),
                            'is_verified' => $product->is_verified,
                            'channel_visibility' => $product->channel_visibility,
                        ];
                        if ($request->hasFile("variants.{$variantId}.image")) {
                            $this->imageService->deleteProductImageFolder($variant->id, $variant->image_path);
                            $imageResult = $this->imageService->processProductImageVariants($request->file("variants.{$variantId}.image"), $variant->id);
                            $variantUpdate['image_path'] = $imageResult['original'];
                            $variantUpdate['image'] = $imageResult;
                        }
                        
                        // Update variant
                        $variant->update($variantUpdate);
                        
                        // Sync attribute values
                        $variant->attributeValues()->sync($variantData['attribute_value_ids']);
                    }
                }
            }
            
            // Create new variants
            if ($request->has('new_variants')) {
                foreach ($request->new_variants as $index => $variantData) {
                    // Get attribute values for variant name
                    $attributeValues = AttributeValue::whereIn('id', $variantData['attribute_value_ids'])
                        ->with('attribute')
                        ->get();
                    $variationName = $attributeValues->map(function($av) {
                        return $av->attribute->name . ': ' . $av->value;
                    })->implode(' - ');
                    
                    // Generate slug for variant
                    $slug = \Illuminate\Support\Str::slug($product->name . ' ' . $variationName);
                    $originalSlug = $slug;
                    $counter = 1;
                    while (Product::where('slug', $slug)->exists()) {
                        $slug = $originalSlug . '-' . $counter;
                        $counter++;
                    }
                    
                    // Validate SKU uniqueness
                    $sku = $variantData['sku'];
                    $skuCounter = 1;
                    $originalSku = $sku;
                    while (Product::where('sku', $sku)->exists()) {
                        $sku = $originalSku . '-' . $skuCounter;
                        $skuCounter++;
                    }
                    
                    // Generate barcode if not provided
                    $barcode = $variantData['barcode'] ?? null;
                    if (empty($barcode)) {
                        $barcode = $this->generateBarcode(Product::class);
                    }
                    
                    // Create variant as Product (image set after create if uploaded)
                    $variant = Product::create([
                        'parent_id' => $product->id,
                        'product_type' => 'variant',
                        'category_id' => $product->category_id,
                        'unit_id' => $product->unit_id,
                        'tax_id' => $product->tax_id,
                        'tax_rate_snapshot' => $product->tax_rate_snapshot,
                        'brand_id' => $product->brand_id,
                        'name' => $product->name . ' - ' . $variationName,
                        'slug' => $slug,
                        'sku' => $sku,
                        'barcode' => $barcode,
                        'hsn_code' => $product->hsn_code,
                        'shipping_days' => $variantData['shipping_days'] ?? $product->shipping_days,
                        'price' => $variantData['price'],
                        'mrp' => $variantData['mrp'] ?? null,
                        'purchase_price' => $variantData['purchase_price'] ?? null,
                        'wholesale_price' => $variantData['wholesale_price'] ?? null,
                        'opening_stock' => $variantData['opening_stock'] ?? 0,
                        'current_stock' => $variantData['opening_stock'] ?? 0,
                        'image_path' => $product->image_path,
                        'short_desc' => $product->short_desc,
                        'long_desc' => $product->long_desc,
                        'tags' => $product->tags ?? $request->input('tags'),
                        'is_active' => true,
                        'is_verified' => $product->is_verified,
                        'channel_visibility' => $product->channel_visibility,
                        'is_featured' => false,
                        'is_prebooking' => $product->is_prebooking,
                    ]);
                    
                    // Handle variant image upload (folder: products/{variant_id}/)
                    if ($request->hasFile("new_variants.{$index}.image")) {
                        $imageResult = $this->imageService->processProductImageVariants($request->file("new_variants.{$index}.image"), $variant->id);
                        $variant->update([
                            'image_path' => $imageResult['original'],
                            'image' => $imageResult,
                        ]);
                    }
                    
                    // Attach attribute values
                    $variant->attributeValues()->attach($variantData['attribute_value_ids']);
                    
                    // Create opening stock movement
                    if ($variant->opening_stock > 0) {
                        VariantStockMovement::create([
                            'product_id' => $variant->id,
                            'type' => VariantStockMovement::TYPE_OPENING_STOCK,
                            'quantity' => $variant->opening_stock,
                            'notes' => 'Opening stock',
                            'created_by' => auth()->check() ? auth()->id() : 1,
                        ]);
                        $variant->updateCurrentStock();
                    }
                }
            }
            
            DB::commit();
            
            $product->load('media');
            
            return redirect()->route('admin.products.variants.index', $product->id)
                ->with('success', 'Variant product updated successfully.');
        } catch (\Exception $e) {
            DB::rollBack();
            return back()->withErrors(['error' => 'Failed to update variant product: ' . $e->getMessage()])->withInput();
        }
    }

    /**
     * Show all variants for a variant product
     */
    public function showVariants(Product $product)
    {
        if ($product->product_type !== 'variant') {
            return redirect()->route('admin.products.index')
                ->with('error', 'This is not a variant product.');
        }

        $variants = $product->variants()->with('attributeValues.attribute')->get();
        $attributes = Attribute::with('activeValues')->active()->get();

        return view('admin.products.variants.index', compact('product', 'variants', 'attributes'));
    }


    /**
     * Show the form for editing a variant item
     */
    public function editVariantItem(Product $variant): View
    {
        if (is_null($variant->parent_id)) {
            return redirect()->route('admin.products.index')
                ->with('error', 'This is not a variant product.');
        }
        
        $variant->load('parent', 'attributeValues.attribute');
        $attributes = Attribute::with('activeValues')->active()->get();

        return view('admin.products.variants.edit', compact('variant', 'attributes'));
    }

    /**
     * Update a variant item
     */
    public function updateVariantItem(Request $request, Product $variant): RedirectResponse
    {
        if (is_null($variant->parent_id)) {
            return redirect()->route('admin.products.index')
                ->with('error', 'This is not a variant product.');
        }
        
        $request->validate([
            'attribute_value_ids' => ['required', 'array', $this->arrayMinCountRule(1)],
            'attribute_value_ids.*' => 'exists:attribute_values,id',
            'sku' => [
                'nullable',
                'string',
                $this->maxLengthRule(191),
                \Illuminate\Validation\Rule::unique('products', 'sku')->ignore($variant->id),
            ],
            'price' => ['required', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'purchase_price' => ['nullable', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'wholesale_price' => ['nullable', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'mrp' => ['nullable', 'numeric', $this->decimalRangeRule(0, 999999.99)],
            'barcode' => ['nullable', 'string', $this->maxLengthRule(191), 'unique:products,barcode,' . $variant->id],
            'hsn_code' => ['nullable', 'string', $this->maxLengthRule(50)],
            'warranty_months' => ['nullable', 'integer', $this->integerRangeRule(0)],
            'shipping_days' => ['nullable', 'integer', $this->integerRangeRule(0)],
            'image' => 'nullable|image|mimes:jpeg,png,jpg,gif,webp|max:5120',
            'tags' => ['nullable', 'string', $this->maxLengthRule(500)],
            'is_verified' => 'boolean',
            'channel_visibility' => ['required', 'string', \Illuminate\Validation\Rule::in(\App\Models\Product::CHANNEL_VISIBILITIES)],
        ]);

        $data = $request->all();
        $data['channel_visibility'] = $request->input('channel_visibility', $variant->channel_visibility ?? Product::CHANNEL_BOTH);
        // Only pass fillable attributes to update
        $data = array_intersect_key($data, array_flip($variant->getFillable()));
        $data['tags'] = $request->input('tags') ?? $variant->tags;
        
        // Auto-generate SKU if not provided
        if (empty($data['sku']) || trim($data['sku']) === '') {
            do {
                $data['sku'] = 'VAR-' . $variant->parent_id . '-' . time() . '-' . rand(1000, 9999);
            } while (Product::where('sku', $data['sku'])->where('id', '!=', $variant->id)->exists());
        }

        // Update variant name if attribute values changed
        if ($request->has('attribute_value_ids')) {
            $attributeValues = AttributeValue::whereIn('id', $request->attribute_value_ids)
                ->with('attribute')
                ->get();
            $variationName = $attributeValues->map(function($av) {
                return $av->attribute->name . ': ' . $av->value;
            })->implode(' - ');
            
            $parent = $variant->parent;
            $data['name'] = $parent->name . ' - ' . $variationName;
            
            // Update slug if name changed
            $slug = \Illuminate\Support\Str::slug($data['name']);
            $originalSlug = $slug;
            $counter = 1;
            while (Product::where('slug', $slug)->where('id', '!=', $variant->id)->exists()) {
                $slug = $originalSlug . '-' . $counter;
                $counter++;
            }
            $data['slug'] = $slug;
        }

        // Handle image upload (folder: products/{variant_id}/)
        if ($request->hasFile('image')) {
            $this->imageService->deleteProductImageFolder($variant->id, $variant->image_path);
            $imageResult = $this->imageService->processProductImageVariants($request->file('image'), $variant->id);
            $data['image_path'] = $imageResult['original'];
            $data['image'] = $imageResult;
        }

        DB::beginTransaction();
        try {
            $variant->update($data);

            // Sync attribute values
            if ($request->has('attribute_value_ids')) {
                $variant->attributeValues()->sync($request->attribute_value_ids);
            }

            DB::commit();

            return redirect()->route('admin.products.variants.index', $variant->parent_id)
                ->with('success', 'Variant updated successfully.');
        } catch (\Exception $e) {
            DB::rollBack();
            return back()->withErrors(['error' => 'Failed to update variant: ' . $e->getMessage()]);
        }
    }

    /**
     * Delete a variant item
     */
    public function destroyVariantItem(Product $variant): RedirectResponse
    {
        if (is_null($variant->parent_id)) {
            return redirect()->route('admin.products.index')
                ->with('error', 'This is not a variant product.');
        }
        
        $productId = $variant->parent_id;

        // Delete variant image folder (and legacy single file if any)
        $this->imageService->deleteProductImageFolder($variant->id, $variant->image_path);

        $variant->delete();

        return redirect()->route('admin.products.variants.index', $productId)
            ->with('success', 'Variant deleted successfully.');
    }

    /**
     * Save user's column preferences
     */
    public function saveColumnPreferences(Request $request)
    {
        $request->validate([
            'columns' => 'required|array',
            'columns.*' => 'string',
        ]);

        $user = auth()->user();
        if (!$user) {
            return response()->json([
                'success' => false,
                'message' => 'User not authenticated'
            ], 401);
        }

        // Get available columns to validate
        $availableColumns = ['image', 'id', 'name', 'sku', 'category', 'brand', 'hsn', 'shipping_days', 'price', 'mrp', 'purchase_price', 'wholesale_price', 'status', 'actions'];
        $availableColumns = array_merge(
            array_slice($availableColumns, 0, array_search('price', $availableColumns) + 1),
            ['stock', 'opening_stock'],
            array_slice($availableColumns, array_search('price', $availableColumns) + 1)
        );
        $availableColumns = array_merge($availableColumns, ['unit', 'tax', 'tags', 'short_desc', 'featured', 'prebooking', 'created_at']);

        // Validate columns
        $columns = array_filter($request->columns, function($col) use ($availableColumns) {
            return in_array($col, $availableColumns);
        });

        // Always include image and actions
        if (!in_array('image', $columns)) {
            $columns[] = 'image';
        }
        if (!in_array('actions', $columns)) {
            $columns[] = 'actions';
        }

        // Save preferences
        if ($user->setProductColumnPreferences(array_values($columns))) {
            return response()->json([
                'success' => true,
                'message' => 'Column preferences saved successfully',
                'columns' => $columns
            ]);
        }

        return response()->json([
            'success' => false,
            'message' => 'Failed to save preferences'
        ], 500);
    }

    /**
     * Validate non-negative decimal range without using min/max numeric rules.
     */
    private function decimalRangeRule(float $min, float $max): \Closure
    {
        return static function (string $attribute, mixed $value, \Closure $fail) use ($min, $max): void {
            if ($value === null || $value === '') {
                return;
            }

            if (!is_numeric($value)) {
                return; // numeric rule handles this
            }

            $number = (float) $value;
            if ($number < $min || $number > $max) {
                $fail("The {$attribute} must be between {$min} and {$max}.");
            }
        };
    }

    /**
     * Validate integer range without using min/max rules.
     */
    private function integerRangeRule(int $min, ?int $max = null): \Closure
    {
        return static function (string $attribute, mixed $value, \Closure $fail) use ($min, $max): void {
            if ($value === null || $value === '') {
                return;
            }

            if (filter_var($value, FILTER_VALIDATE_INT) === false) {
                return; // integer rule handles this
            }

            $number = (int) $value;
            if ($number < $min || ($max !== null && $number > $max)) {
                if ($max === null) {
                    $fail("The {$attribute} must be at least {$min}.");
                    return;
                }

                $fail("The {$attribute} must be between {$min} and {$max}.");
            }
        };
    }

    /**
     * Validate maximum string length without Laravel max rule.
     */
    private function maxLengthRule(int $max): \Closure
    {
        return static function (string $attribute, mixed $value, \Closure $fail) use ($max): void {
            if ($value === null || $value === '') {
                return;
            }

            if (!is_string($value)) {
                return; // string rule handles this
            }

            if (mb_strlen($value) > $max) {
                $fail("The {$attribute} field must not exceed {$max} characters.");
            }
        };
    }

    /**
     * Validate minimum array item count without Laravel min rule.
     */
    private function arrayMinCountRule(int $min): \Closure
    {
        return static function (string $attribute, mixed $value, \Closure $fail) use ($min): void {
            if (!is_array($value)) {
                return; // array rule handles this
            }

            if (count($value) < $min) {
                $fail("The {$attribute} field must contain at least {$min} item(s).");
            }
        };
    }

    /**
     * Validate maximum array item count without Laravel max rule.
     */
    private function arrayMaxCountRule(int $max): \Closure
    {
        return static function (string $attribute, mixed $value, \Closure $fail) use ($max): void {
            if (!is_array($value)) {
                return; // array rule handles this
            }

            if (count($value) > $max) {
                $fail("The {$attribute} field must not contain more than {$max} item(s).");
            }
        };
    }

    public static function generateBarcode(
        string $modelClass,
        int $length = 8,
        string $column = 'barcode'
    ): string {
        do {
            $barcode = str_pad(
                random_int(0, (10 ** $length) - 1),
                $length,
                '0',
                STR_PAD_LEFT
            );
        } while ($modelClass::where($column, $barcode)->exists());

        return $barcode;
    }
}
