<?php

namespace App\Http\Controllers\Tenant;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Tenant\Product;
use App\Models\Tenant\Category;
use App\Models\Tenant\Brand;
use App\Models\Tenant\Unit;
use App\Models\Tenant\ProductVariant;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class ProductController extends Controller
{
    public function index(Request $request)
    {
        $query = Product::with(['category', 'brand', 'variants'])->latest();

        // Filters
        if ($request->filled('category_id')) {
            $query->where('category_id', $request->category_id);
        }

        if ($request->filled('brand_id')) {
            $query->where('brand_id', $request->brand_id);
        }

        if ($request->filled('search')) {
            $query->where(function($q) use ($request) {
                $q->where('name', 'like', '%' . $request->search . '%')
                  ->orWhere('sku', 'like', '%' . $request->search . '%');
            });
        }

        $products = $query->paginate(10)->withQueryString();
        
        $categories = Category::all();
        $brands = Brand::all();

        return view('tenant.products.index', compact('products', 'categories', 'brands'));
    }

    public function create()
    {
        $categories = Category::all();
        $brands = Brand::all();
        $units = Unit::all();
        return view('tenant.products.create', compact('categories', 'brands', 'units'));
    }

    public function store(Request $request)
    {
        // 1. Basic Validation
        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'category_id' => 'nullable|exists:tenant.categories,id',
            'brand_id' => 'nullable|exists:tenant.brands,id',
            'unit_id' => 'required|exists:tenant.units,id',
            'has_variants' => 'boolean',
            'image' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048', // Validation for image
            
            // Simple Product Fields (if has_variants = false)
            'sku' => 'required_if:has_variants,false|nullable|string|max:255',
            'price' => 'required_if:has_variants,false|nullable|numeric|min:0',
            'cost' => 'nullable|numeric|min:0',
            'stock' => 'nullable|integer|min:0',

            // Complex Product Fields (if has_variants = true)
            'product_units' => 'nullable|array', // Custom units like Case/Pack
            'variants' => 'required_if:has_variants,true|array',
        ]);

        try {
            DB::beginTransaction();

            $imagePath = null;
            if ($request->hasFile('image')) {
                $imagePath = $request->file('image')->store('products', 'public');
            }

            // 2. Create Product
            $product = Product::create([
                'name' => $validated['name'],
                'category_id' => $validated['category_id'] ?? null,
                'brand_id' => $validated['brand_id'] ?? null,
                'unit_id' => $validated['unit_id'],
                'has_variants' => $request->has_variants == '1' || $request->has_variants === true,
                'image' => $imagePath,
                'manufacture_date' => $request->manufacture_date,
                'expiry_date' => $request->expiry_date,
            ]);

            // 3. Create Custom Units (if any)
            $unitMap = []; // Map unit name to ID (including base unit)
            
            // Create Base Unit Wrapper
            $baseUnitGlobal = Unit::find($validated['unit_id']);
            $baseUnitWrapper = $product->productUnits()->create([
                'name' => $baseUnitGlobal->name,
                'conversion_factor' => 1,
                'is_base' => true,
                'is_purchase' => true,
                'is_sale' => true,
            ]);
            $unitMap['Base Unit'] = $baseUnitWrapper->id; // Fallback key
            $unitMap[$baseUnitGlobal->name] = $baseUnitWrapper->id; // Actual name key
            
            if ($request->has('product_units') && is_array($request->product_units)) {
                foreach ($request->product_units as $pUnit) {
                    if (!empty($pUnit['name'])) {
                        $createdUnit = $product->productUnits()->create([
                            'name' => $pUnit['name'],
                            'conversion_factor' => $pUnit['conversion_factor'] ?? 1,
                            'is_base' => false,
                            'is_purchase' => isset($pUnit['is_purchase']),
                            'is_sale' => isset($pUnit['is_sale']),
                        ]);
                        $unitMap[$pUnit['name']] = $createdUnit->id;
                    }
                }
            }

            // 4. Handle Variants
            if ($product->has_variants) {
                foreach ($request->variants as $variantData) {
                    // Create Variant
                    $variant = $product->variants()->create([
                        'name' => $variantData['name'] ?? $product->name,
                        'sku' => $variantData['sku'],
                        'stock' => $variantData['stock'] ?? 0,
                        'is_active' => true,
                    ]);

                    // Add Attributes
                    if (isset($variantData['attributes']) && is_array($variantData['attributes'])) {
                        foreach ($variantData['attributes'] as $attr) {
                            $variant->attributes()->create([
                                'name' => $attr['name'],
                                'value' => $attr['value'],
                            ]);
                        }
                    }

                    // Add Prices
                    if (isset($variantData['prices']) && is_array($variantData['prices'])) {
                        foreach ($variantData['prices'] as $priceData) {
                            $unitId = null;
                            if (isset($unitMap[$priceData['unit_name']])) {
                                $unitId = $unitMap[$priceData['unit_name']];
                            }
                            
                            // If unit_id is found (custom unit), create price. 
                            // If it's base unit, we might not have a product_unit_id if we didn't create a ProductUnit wrapper for base.
                            // For simplicity, let's assume we create a ProductUnit wrapper for the base unit too, or we handle null.
                            // Better: Create a ProductUnit for the base unit as well in step 3.
                            
                            if ($unitId) {
                                $variant->prices()->create([
                                    'product_unit_id' => $unitId,
                                    'price' => $priceData['price'] ?? 0,
                                    'cost' => $priceData['cost'] ?? 0,
                                ]);
                            }
                        }
                    }
                }
            } else {
                // Simple Product (Single Variant)
                $variant = $product->variants()->create([
                    'name' => $product->name,
                    'sku' => $validated['sku'],
                    'price' => $validated['price'], // Legacy field support
                    'cost' => $validated['cost'] ?? 0,
                    'stock' => $validated['stock'] ?? 0,
                ]);

                // Also create a price record for the base unit to maintain consistency
                if ($baseUnitWrapper) {
                    $variant->prices()->create([
                        'product_unit_id' => $baseUnitWrapper->id,
                        'price' => $validated['price'],
                        'cost' => $validated['cost'] ?? 0,
                    ]);
                }
            }

            DB::commit();

            $message = 'Product created successfully.';
            if ($request->input('action') === 'save_and_add_another') {
                return redirect()->route('tenant.products.create')->with('success', $message);
            }

            return redirect()->route('tenant.products.index')->with('success', $message);

        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Product Creation Error: ' . $e->getMessage());
            return back()->with('error', 'Failed to create product: ' . $e->getMessage())->withInput();
        }
    }

    public function edit($id)
    {
        $product = Product::findOrFail($id);
        $product->load(['category', 'brand', 'variants.attributes', 'variants.prices.productUnit', 'productUnits']);
        $categories = Category::all();
        $brands = Brand::all();
        $units = Unit::all();
        return view('tenant.products.edit', compact('product', 'categories', 'brands', 'units'));
    }

    public function update(Request $request, $id)
    {
        $product = Product::findOrFail($id);

        // 1. Basic Validation
        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'category_id' => 'nullable|exists:tenant.categories,id',
            'brand_id' => 'nullable|exists:tenant.brands,id',
            'unit_id' => 'required|exists:tenant.units,id',
            'has_variants' => 'boolean',
            'image' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048',
            
            // Simple Product Fields
            'sku' => 'required_if:has_variants,false|nullable|string|max:255',
            'price' => 'required_if:has_variants,false|nullable|numeric|min:0',
            'cost' => 'nullable|numeric|min:0',
            'stock' => 'nullable|integer|min:0',

            // Complex Product Fields
            'product_units' => 'nullable|array',
            'variants' => 'required_if:has_variants,true|array',
        ]);

        try {
            DB::beginTransaction();

            // Handle Image
            if ($request->hasFile('image')) {
                // Delete old image if exists
                if ($product->image) {
                    \Illuminate\Support\Facades\Storage::disk('public')->delete($product->image);
                }
                $product->image = $request->file('image')->store('products', 'public');
            }

            // Update Basic Info
            $product->update([
                'name' => $validated['name'],
                'category_id' => $validated['category_id'] ?? null,
                'brand_id' => $validated['brand_id'] ?? null,
                'unit_id' => $validated['unit_id'],
                'has_variants' => $request->has_variants == '1' || $request->has_variants === true,
                'manufacture_date' => $request->manufacture_date,
                'expiry_date' => $request->expiry_date,
            ]);

            // Handle Unit Change (if base unit changed, update the base wrapper)
            // Ideally we check if unit_id changed, but we can just update the is_base unit wrapper
            $baseUnitGlobal = Unit::find($validated['unit_id']);
            $product->productUnits()->where('is_base', true)->update([
                'name' => $baseUnitGlobal->name,
            ]);
            
            // Sync Custom Units
            // Strategy: Delete non-base units and recreate (simpler for now, or careful sync)
            // To preserve IDs for price linking, we should try to update/create
            // But since the UI might just send a list, let's look at names. 
            // For this implementation, let's clear non-base units and recreate them. 
            // WARNING: This breaks variant price links if they reference product_unit_id.
            // We must map old unit names to IDs or update carefully.
            
            // Better: Re-build the unit map.
            $unitMap = [];
            $baseWrapper = $product->productUnits()->where('is_base', true)->first();
            $unitMap['Base Unit'] = $baseWrapper->id;
            $unitMap[$baseUnitGlobal->name] = $baseWrapper->id;

            // Delete old non-base units? 
            // If we delete units, we delete linked prices (cascade?). 
            // Let's assume we delete and recreate prices too for simplicity in this "Reset" approach,
            // OR we try to match by name.
            
            $existingUnits = $product->productUnits()->where('is_base', false)->get()->keyBy('name');
            $validUnitIds = [$baseWrapper->id];

            if ($request->has('product_units') && is_array($request->product_units)) {
                foreach ($request->product_units as $pUnit) {
                    if (!empty($pUnit['name'])) {
                        if ($existingUnits->has($pUnit['name'])) {
                            // Update existing
                            $u = $existingUnits[$pUnit['name']];
                            $u->update([
                                'conversion_factor' => $pUnit['conversion_factor'] ?? 1,
                                'is_purchase' => isset($pUnit['is_purchase']),
                                'is_sale' => isset($pUnit['is_sale']),
                            ]);
                            $unitMap[$pUnit['name']] = $u->id;
                            $validUnitIds[] = $u->id;
                        } else {
                            // Create new
                            $createdUnit = $product->productUnits()->create([
                                'name' => $pUnit['name'],
                                'conversion_factor' => $pUnit['conversion_factor'] ?? 1,
                                'is_base' => false,
                                'is_purchase' => isset($pUnit['is_purchase']),
                                'is_sale' => isset($pUnit['is_sale']),
                            ]);
                            $unitMap[$pUnit['name']] = $createdUnit->id;
                            $validUnitIds[] = $createdUnit->id;
                        }
                    }
                }
            }
            
            // Remove units not in the request
            $product->productUnits()->where('is_base', false)->whereNotIn('id', $validUnitIds)->delete();


            // Handle Variants
            if (!$product->has_variants) {
                // switched to Simple or stayed Simple
                $firstVariant = $product->variants()->first();
                if (!$firstVariant) {
                    $firstVariant = $product->variants()->create([
                        'name' => $product->name,
                        'sku' => $validated['sku'],
                        'stock' => $validated['stock'] ?? 0,
                    ]);
                } else {
                    $firstVariant->update([
                        'name' => $product->name,
                        'sku' => $validated['sku'],
                        'stock' => $validated['stock'] ?? 0,
                    ]);
                }
                
                // Sync Prices for Simple Product
                $firstVariant->prices()->updateOrCreate(
                    ['product_unit_id' => $baseWrapper->id],
                    ['price' => $validated['price'], 'cost' => $validated['cost'] ?? 0]
                );

                // Delete other variants
                $product->variants()->where('id', '!=', $firstVariant->id)->delete();

            } else {
                // Complex (variant) product
                $postedVariantIds = [];
                
                if ($request->has('variants') && is_array($request->variants)) {
                    foreach ($request->variants as $variantData) {
                        $variant = null;
                        if (!empty($variantData['id'])) {
                            $variant = $product->variants()->find($variantData['id']);
                        }

                        if ($variant) {
                            // Update existing
                            $variant->update([
                                'name' => $variantData['name'] ?? $product->name,
                                'sku' => $variantData['sku'],
                                'stock' => $variantData['stock'] ?? 0,
                                'is_active' => true,
                            ]);
                        } else {
                            // Create new
                            $variant = $product->variants()->create([
                                'name' => $variantData['name'] ?? $product->name,
                                'sku' => $variantData['sku'],
                                'stock' => $variantData['stock'] ?? 0,
                                'is_active' => true,
                            ]);
                        }
                        
                        $postedVariantIds[] = $variant->id;

                        // Sync Attributes
                        // Attributes are small, so delete and recreate is fine for attributes themselves
                        $variant->attributes()->delete();
                        if (isset($variantData['attributes']) && is_array($variantData['attributes'])) {
                            foreach ($variantData['attributes'] as $attr) {
                                $variant->attributes()->create([
                                    'name' => $attr['name'],
                                    'value' => $attr['value'],
                                ]);
                            }
                        }

                        // Sync Prices
                        // Instead of deleting all, let's sync them to avoid breaking potential FKs or history
                        $validPriceUnitIds = [];
                        if (isset($variantData['prices']) && is_array($variantData['prices'])) {
                            foreach ($variantData['prices'] as $priceData) {
                                $unitName = $priceData['unit_name'] ?? null;
                                $productUnitId = $unitMap[$unitName] ?? null;
                                
                                if ($productUnitId) {
                                    $variant->prices()->updateOrCreate(
                                        ['product_unit_id' => $productUnitId],
                                        [
                                            'price' => $priceData['price'] ?? 0,
                                            'cost' => $priceData['cost'] ?? 0,
                                        ]
                                    );
                                    $validPriceUnitIds[] = $productUnitId;
                                }
                            }
                        }
                        // Remove prices for units no longer associated with this variant
                        $variant->prices()->whereNotIn('product_unit_id', $validPriceUnitIds)->delete();
                    }
                }
                
                // Delete variants not in the request
                $product->variants()->whereNotIn('id', $postedVariantIds)->delete();
            }

            DB::commit();
            return redirect()->route('tenant.products.index')->with('success', 'Product updated successfully.');

        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Product Update Error: ' . $e->getMessage());
            return back()->with('error', 'Failed to update product: ' . $e->getMessage())->withInput();
        }
    }

    public function show($id)
    {
        $product = Product::with([
            'category', 
            'brand', 
            'unit',
            'variants.attributes', 
            'variants.prices.productUnit',
            'productUnits'
        ])->findOrFail($id);
        
        return view('tenant.products.show', compact('product'));
    }

    public function destroy($id)
    {
        $product = Product::findOrFail($id);
        $product->delete();
        return redirect()->route('tenant.products.index')->with('success', 'Product deleted successfully.');
    }

    public function downloadTemplate()
    {
        $headers = [
            "Content-type" => "text/csv",
            "Content-Disposition" => "attachment; filename=product_import_template.csv",
            "Pragma" => "no-cache",
            "Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
            "Expires" => "0"
        ];

        $columns = ['Name', 'Category', 'Brand', 'Base Unit', 'SKU', 'Selling Price', 'Cost Price', 'Stock'];

        $callback = function() use ($columns) {
            $file = fopen('php://output', 'w');
            fputcsv($file, $columns);
            fclose($file);
        };

        return response()->stream($callback, 200, $headers);
    }

    public function import(Request $request)
    {
        $request->validate([
            'file' => 'required|file|mimes:csv,txt,xlsx,xls',
        ]);

        $file = $request->file('file');
        $path = $file->getRealPath();

        // Simple CSV handling for now. If user uploads excel, we might need a library or conversion.
        // For now, assuming CSV as per template.
        
        $data = array_map('str_getcsv', file($path));
        $header = array_shift($data); // Remove header row

        // Map header to index if needed, or assume fixed order from template
        // Template: Name, Category, Brand, Base Unit, SKU, Selling Price, Cost Price, Stock
        
        DB::beginTransaction();
        try {
            foreach ($data as $row) {
                if (count($row) < 8) continue; // Skip invalid rows

                $name = $row[0];
                $categoryName = $row[1];
                $brandName = $row[2];
                $unitName = $row[3];
                $sku = $row[4];
                $price = $row[5];
                $cost = $row[6];
                $stock = $row[7];

                if (empty($name) || empty($unitName)) continue;

                // Find or Create Relations
                $category = !empty($categoryName) ? Category::firstOrCreate(['name' => $categoryName]) : null;
                $brand = !empty($brandName) ? Brand::firstOrCreate(['name' => $brandName]) : null;
                $unit = Unit::firstOrCreate(['name' => $unitName], ['short_name' => substr($unitName, 0, 3)]); // Simple fallback for short_name

                // Create Product
                $product = Product::create([
                    'name' => $name,
                    'category_id' => $category ? $category->id : null,
                    'brand_id' => $brand ? $brand->id : null,
                    'unit_id' => $unit->id,
                    'has_variants' => false,
                ]);

                // Create Base Unit Wrapper
                $baseUnitWrapper = $product->productUnits()->create([
                    'name' => $unit->name,
                    'conversion_factor' => 1,
                    'is_base' => true,
                    'is_purchase' => true,
                    'is_sale' => true,
                ]);

                // Create Variant
                $product->variants()->create([
                    'name' => $name,
                    'sku' => $sku,
                    'price' => $price,
                    'cost' => $cost,
                    'stock' => $stock,
                    'is_active' => true,
                ]);
            }
            
            DB::commit();
            return back()->with('success', 'Products imported successfully.');
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Import Error: ' . $e->getMessage());
            return back()->with('error', 'Import failed: ' . $e->getMessage());
        }
    }
}
