<?php

namespace App\Http\Controllers;

use App\Models\Category;
use App\Models\InventoryLog;
use App\Models\PriceAdjustmentDetail;
use App\Models\PriceAdjustmentLog;
use App\Models\Product;
use App\Models\ProductPriceHistory;
use App\Models\Supplier;
use App\Models\SupplierPayment;
use Carbon\Carbon;
use Illuminate\Http\Request;

class InventoryController extends Controller
{
    public function index(Request $request)
    {
        $query = InventoryLog::with(['product', 'user', 'supplier']);

        if ($request->barcode) {
            $productIds = Product::where('barcode', 'like', '%'.$request->barcode.'%')->pluck('id');
            $query->whereIn('product_id', $productIds);
        }

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

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

        if ($request->date_from) {
            $query->whereDate('created_at', '>=', $request->date_from);
        }

        if ($request->date_to) {
            $query->whereDate('created_at', '<=', $request->date_to);
        }

        $logs = $query->orderBy('created_at', 'desc')->paginate(30);
        $products = Product::orderBy('name')->get();

        return view('inventory.index', compact('logs', 'products'));
    }

    public function stockInForm()
    {
        $products = Product::active()->with('unitOfMeasure')->orderBy('name')->get();
        $suppliers = Supplier::active()->orderBy('name')->get();

        return view('inventory.stock-in', compact('products', 'suppliers'));
    }

    public function stockIn(Request $request)
    {
        $request->validate([
            'supplier_id' => 'required|string',
            'reference_number' => 'nullable|string|max:255',
            'notes' => 'nullable|string',
            'pay_supplier' => 'nullable|in:now,later',
            'cash_amount' => 'nullable|numeric|min:0',
            'mpesa_amount' => 'nullable|numeric|min:0',
            'card_amount' => 'nullable|numeric|min:0',
            'items' => 'required|array|min:1',
            'items.*.product_id' => 'required|exists:products,id',
            'items.*.quantity' => 'required|numeric|min:0.01',
            'items.*.unit_cost' => 'nullable|numeric|min:0',
        ], [
            'supplier_id.required' => 'Please select a supplier.',
            'items.required' => 'Please add at least one product.',
        ]);

        $supplierId = $request->supplier_id === 'none' ? null : $request->supplier_id;
        $itemsProcessed = 0;

        foreach ($request->items as $item) {
            if (empty($item['product_id'])) {
                continue;
            }

            $product = Product::findOrFail($item['product_id']);
            $previousStock = (float) $product->stock_quantity;
            $newStock = $previousStock + (float) $item['quantity'];
            $oldCostPrice = (float) $product->cost_price;

            $updateData = ['stock_quantity' => $newStock];

            if (isset($item['unit_cost']) && $item['unit_cost'] !== null && $item['unit_cost'] !== '') {
                $newCostPrice = (float) $item['unit_cost'];
                $updateData['cost_price'] = $newCostPrice;

                if ($oldCostPrice !== $newCostPrice) {
                    ProductPriceHistory::create([
                        'product_id' => $product->id,
                        'user_id' => auth()->id(),
                        'old_cost_price' => $oldCostPrice,
                        'new_cost_price' => $newCostPrice,
                        'old_selling_price' => $product->selling_price,
                        'new_selling_price' => $product->selling_price,
                        'reason' => 'Stock In Update',
                    ]);
                }
            }

            $product->update($updateData);

            InventoryLog::create([
                'product_id' => $product->id,
                'user_id' => auth()->id(),
                'supplier_id' => $supplierId,
                'type' => 'stock_in',
                'quantity' => $item['quantity'],
                'previous_stock' => $previousStock,
                'new_stock' => $newStock,
                'unit_cost' => $item['unit_cost'] ?? null,
                'reference_number' => $request->reference_number,
                'notes' => $request->notes,
            ]);

            $itemsProcessed++;
        }

        // Handle supplier payment if applicable
        if ($supplierId && $request->pay_supplier === 'now') {
            $cashAmount = $request->cash_amount ?? 0;
            $mpesaAmount = $request->mpesa_amount ?? 0;
            $cardAmount = $request->card_amount ?? 0;
            $totalPaid = $cashAmount + $mpesaAmount + $cardAmount;

            $supplier = Supplier::find($supplierId);
            if ($supplier && $totalPaid > 0) {
                $currentPaid = $supplier->total_paid ?? 0;
                $supplier->update(['total_paid' => $currentPaid + $totalPaid]);

                $paymentDate = now();
                if ($cashAmount > 0) {
                    SupplierPayment::create([
                        'supplier_id' => $supplier->id,
                        'amount' => $cashAmount,
                        'payment_method' => 'cash',
                        'reference_number' => $request->reference_number,
                        'notes' => 'Payment for stock in',
                        'payment_date' => $paymentDate,
                    ]);
                }
                if ($mpesaAmount > 0) {
                    SupplierPayment::create([
                        'supplier_id' => $supplier->id,
                        'amount' => $mpesaAmount,
                        'payment_method' => 'mpesa',
                        'reference_number' => $request->reference_number,
                        'notes' => 'Payment for stock in',
                        'payment_date' => $paymentDate,
                    ]);
                }
                if ($cardAmount > 0) {
                    SupplierPayment::create([
                        'supplier_id' => $supplier->id,
                        'amount' => $cardAmount,
                        'payment_method' => 'card',
                        'reference_number' => $request->reference_number,
                        'notes' => 'Payment for stock in',
                        'payment_date' => $paymentDate,
                    ]);
                }
            }
        }

        return redirect()->route('inventory.index')->with('success', "Stock added successfully for {$itemsProcessed} product(s).");
    }

    public function adjustmentForm()
    {
        $products = Product::orderBy('name')->get();

        return view('inventory.adjustment', compact('products'));
    }

    public function adjustment(Request $request)
    {
        $request->validate([
            'product_id' => 'required|exists:products,id',
            'quantity' => 'required|integer',
            'notes' => 'required|string',
        ]);

        $product = Product::findOrFail($request->product_id);
        $previousStock = $product->stock_quantity;
        $newStock = $previousStock + $request->quantity;

        if ($newStock < 0) {
            return back()->with('error', 'Stock cannot be negative.');
        }

        $product->update(['stock_quantity' => $newStock]);

        InventoryLog::create([
            'product_id' => $product->id,
            'user_id' => auth()->id(),
            'type' => 'adjustment',
            'quantity' => abs($request->quantity),
            'previous_stock' => $previousStock,
            'new_stock' => $newStock,
            'notes' => $request->notes,
        ]);

        return redirect()->route('inventory.index')->with('success', 'Stock adjusted successfully.');
    }

    public function report(Request $request)
    {
        $query = Product::with('category');

        $products = $query->orderBy('name')->get();

        $totalCost = $products->sum(function ($p) {
            return $p->cost_price * $p->stock_quantity;
        });

        $totalValue = $products->sum(function ($p) {
            return $p->selling_price * $p->stock_quantity;
        });

        $lowStockProducts = $products->filter(function ($p) {
            return $p->isLowStock();
        });

        $profit = $totalValue - $totalCost;

        return view('inventory.report', compact('products', 'totalCost', 'totalValue', 'profit', 'lowStockProducts'));
    }

    public function getLastCost(Request $request)
    {
        $productId = $request->product_id;

        $lastLog = InventoryLog::where('product_id', $productId)
            ->where('type', 'stock_in')
            ->whereNotNull('unit_cost')
            ->orderBy('created_at', 'desc')
            ->first();

        return response()->json([
            'last_cost' => $lastLog ? $lastLog->unit_cost : null,
        ]);
    }

    public function getSupplierBalance(Request $request)
    {
        $supplierId = $request->supplier_id;

        if (! $supplierId) {
            return response()->json([
                'total_ordered' => 0,
                'total_paid' => 0,
                'balance' => 0,
            ]);
        }

        $supplier = Supplier::find($supplierId);

        if (! $supplier) {
            return response()->json([
                'total_ordered' => 0,
                'total_paid' => 0,
                'balance' => 0,
            ]);
        }

        $totalOrdered = InventoryLog::where('supplier_id', $supplierId)
            ->where('type', 'stock_in')
            ->sum(\DB::raw('quantity * unit_cost'));

        $totalPaid = $supplier->total_paid ?? 0;
        $balance = $totalOrdered - $totalPaid;

        return response()->json([
            'total_ordered' => $totalOrdered,
            'total_paid' => $totalPaid,
            'balance' => $balance,
        ]);
    }

    public function priceAdjustmentForm()
    {
        $products = Product::orderBy('name')->get();
        $categories = Category::orderBy('name')->get();

        return view('inventory.price-adjustment', compact('products', 'categories'));
    }

    public function priceAdjustment(Request $request)
    {
        $request->validate([
            'adjustment_type' => 'required|in:percentage,fixed',
            'price_type' => 'required|in:cost,selling,price2,price3,both',
            'adjustment_value' => 'required|numeric|min:0',
            'operation' => 'required|in:increase,decrease',
        ]);

        $productIds = $request->product_ids;

        if (is_string($productIds)) {
            $productIds = json_decode($productIds, true) ?? [];
        }

        if (empty($productIds)) {
            return redirect()->back()->with('error', 'No products selected.');
        }

        $products = Product::whereIn('id', $productIds)->get();
        $updated = 0;
        $priceLog = PriceAdjustmentLog::create([
            'user_id' => auth()->id(),
            'adjustment_type' => $request->adjustment_type,
            'operation' => $request->operation,
            'price_type' => $request->price_type,
            'adjustment_value' => $request->adjustment_value,
            'products_updated' => 0,
            'notes' => $request->notes ?? null,
        ]);

        foreach ($products as $product) {
            $adjustmentValue = (float) $request->adjustment_value;
            $oldCostPrice = $product->cost_price;
            $oldSellingPrice = $product->selling_price;
            $oldPrice2 = $product->price_2 ?? 0;
            $oldPrice3 = $product->price_3 ?? 0;
            $newCostPrice = $oldCostPrice;
            $newSellingPrice = $oldSellingPrice;
            $newPrice2 = $oldPrice2;
            $newPrice3 = $oldPrice3;

            if ($request->adjustment_type === 'percentage') {
                if ($request->operation === 'increase') {
                    if (in_array($request->price_type, ['cost', 'both'])) {
                        $newCostPrice = $product->cost_price + ($product->cost_price * $adjustmentValue / 100);
                    }
                    if (in_array($request->price_type, ['selling', 'both'])) {
                        $newSellingPrice = $product->selling_price + ($product->selling_price * $adjustmentValue / 100);
                    }
                    if (in_array($request->price_type, ['price2', 'both'])) {
                        $newPrice2 = ($product->price_2 ?? 0) + (($product->price_2 ?? 0) * $adjustmentValue / 100);
                    }
                    if (in_array($request->price_type, ['price3', 'both'])) {
                        $newPrice3 = ($product->price_3 ?? 0) + (($product->price_3 ?? 0) * $adjustmentValue / 100);
                    }
                } else {
                    if (in_array($request->price_type, ['cost', 'both'])) {
                        $newCostPrice = max(0, $product->cost_price - ($product->cost_price * $adjustmentValue / 100));
                    }
                    if (in_array($request->price_type, ['selling', 'both'])) {
                        $newSellingPrice = max(0, $product->selling_price - ($product->selling_price * $adjustmentValue / 100));
                    }
                    if (in_array($request->price_type, ['price2', 'both'])) {
                        $newPrice2 = max(0, ($product->price_2 ?? 0) - (($product->price_2 ?? 0) * $adjustmentValue / 100));
                    }
                    if (in_array($request->price_type, ['price3', 'both'])) {
                        $newPrice3 = max(0, ($product->price_3 ?? 0) - (($product->price_3 ?? 0) * $adjustmentValue / 100));
                    }
                }
            } else {
                if ($request->operation === 'increase') {
                    if (in_array($request->price_type, ['cost', 'both'])) {
                        $newCostPrice = $product->cost_price + $adjustmentValue;
                    }
                    if (in_array($request->price_type, ['selling', 'both'])) {
                        $newSellingPrice = $product->selling_price + $adjustmentValue;
                    }
                    if (in_array($request->price_type, ['price2', 'both'])) {
                        $newPrice2 = ($product->price_2 ?? 0) + $adjustmentValue;
                    }
                    if (in_array($request->price_type, ['price3', 'both'])) {
                        $newPrice3 = ($product->price_3 ?? 0) + $adjustmentValue;
                    }
                } else {
                    if (in_array($request->price_type, ['cost', 'both'])) {
                        $newCostPrice = max(0, $product->cost_price - $adjustmentValue);
                    }
                    if (in_array($request->price_type, ['selling', 'both'])) {
                        $newSellingPrice = max(0, $product->selling_price - $adjustmentValue);
                    }
                    if (in_array($request->price_type, ['price2', 'both'])) {
                        $newPrice2 = max(0, ($product->price_2 ?? 0) - $adjustmentValue);
                    }
                    if (in_array($request->price_type, ['price3', 'both'])) {
                        $newPrice3 = max(0, ($product->price_3 ?? 0) - $adjustmentValue);
                    }
                }
            }

            PriceAdjustmentDetail::create([
                'price_adjustment_log_id' => $priceLog->id,
                'product_id' => $product->id,
                'old_cost_price' => $oldCostPrice,
                'new_cost_price' => $newCostPrice,
                'old_selling_price' => $oldSellingPrice,
                'new_selling_price' => $newSellingPrice,
                'old_price_2' => $oldPrice2,
                'new_price_2' => $newPrice2,
                'old_price_3' => $oldPrice3,
                'new_price_3' => $newPrice3,
            ]);

            ProductPriceHistory::create([
                'product_id' => $product->id,
                'user_id' => auth()->id(),
                'price_adjustment_log_id' => $priceLog->id,
                'old_cost_price' => $oldCostPrice,
                'new_cost_price' => $newCostPrice,
                'old_selling_price' => $oldSellingPrice,
                'new_selling_price' => $newSellingPrice,
                'reason' => ucfirst($request->operation).' '.($request->adjustment_type === 'percentage' ? $request->adjustment_value.'%' : 'Kes '.$request->adjustment_value).' on '.$request->price_type.' price',
            ]);

            $product->cost_price = $newCostPrice;
            $product->selling_price = $newSellingPrice;
            $product->price_2 = $newPrice2;
            $product->price_3 = $newPrice3;
            $product->save();
            $updated++;
        }

        $priceLog->update(['products_updated' => $updated]);

        return redirect()->route('inventory.price-adjustment')->with('success', "{$updated} product(s) price updated successfully.");
    }

    public function productPriceHistory(Request $request)
    {
        $dateFrom = $request->date_from ?? Carbon::now()->subMonth()->toDateString();
        $dateTo = $request->date_to ?? Carbon::now()->toDateString();
        $productId = $request->product_id;
        $categoryId = $request->category_id;

        $products = Product::with('category')->orderBy('name')->get();
        $categories = Category::orderBy('name')->get();

        $query = ProductPriceHistory::with(['product.category', 'user', 'priceAdjustmentLog'])
            ->whereBetween('product_price_history.created_at', [$dateFrom, $dateTo.' 23:59:59']);

        if ($productId) {
            $query->where('product_id', $productId);
        }

        if ($categoryId) {
            $query->whereHas('product', function ($q) use ($categoryId) {
                $q->where('category_id', $categoryId);
            });
        }

        $history = $query->orderBy('created_at', 'desc')->paginate(50);

        $selectedProduct = $productId ? Product::with('category')->find($productId) : null;

        $productStats = [];
        if ($productId) {
            $productStats = [
                'total_changes' => ProductPriceHistory::where('product_id', $productId)->count(),
                'current_cost' => $selectedProduct->cost_price ?? 0,
                'current_selling' => $selectedProduct->selling_price ?? 0,
                'first_price' => ProductPriceHistory::where('product_id', $productId)->orderBy('created_at', 'asc')->first(),
                'last_change' => ProductPriceHistory::where('product_id', $productId)->orderBy('created_at', 'desc')->first(),
            ];
        }

        return view('inventory.product-price-history', compact(
            'history', 'dateFrom', 'dateTo', 'productId', 'categoryId',
            'products', 'categories', 'selectedProduct', 'productStats'
        ));
    }

    public function exportProductPriceHistory(Request $request)
    {
        $query = ProductPriceHistory::with(['product.category', 'user'])
            ->whereBetween('product_price_history.created_at', [
                $request->date_from ?? Carbon::now()->subMonth()->toDateString(),
                ($request->date_to ?? Carbon::now()->toDateString()).' 23:59:59',
            ]);

        if ($request->product_id) {
            $query->where('product_id', $request->product_id);
        }
        if ($request->category_id) {
            $query->whereHas('product', function ($q) use ($request) {
                $q->where('category_id', $request->category_id);
            });
        }

        $history = $query->orderBy('created_at', 'desc')->get();

        $csvData = "Date,Time,Product,SKU,Category,Old Cost,New Cost,Cost Change,Cost Change %,Old Selling,New Selling,Selling Change,Selling Change %,User,Reason\n";

        foreach ($history as $h) {
            $csvData .= sprintf("%s,%s,%s,%s,%s,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%s,%s\n",
                $h->created_at->format('Y-m-d'),
                $h->created_at->format('H:i:s'),
                $h->product->name ?? '',
                $h->product->sku ?? '',
                $h->product->category->name ?? '',
                $h->old_cost_price,
                $h->new_cost_price,
                $h->cost_change,
                $h->cost_change_percent,
                $h->old_selling_price,
                $h->new_selling_price,
                $h->selling_change,
                $h->selling_change_percent,
                $h->user->name ?? 'System',
                str_replace(',', ';', $h->reason ?? '')
            );
        }

        return response()->streamDownload(function () use ($csvData) {
            echo $csvData;
        }, 'product_price_history_'.date('Y-m-d').'.csv', ['Content-Type' => 'text/csv']);
    }

    public function reconciliation(Request $request)
    {
        $products = Product::with(['category', 'unitOfMeasure'])->orderBy('name')->get();

        $categoryId = $request->category_id;
        $stockFilter = $request->stock_filter;
        $search = $request->search;

        if ($search) {
            $searchTerm = strtolower($search);
            $products = $products->filter(function ($p) use ($searchTerm) {
                return str_contains(strtolower($p->name), $searchTerm) ||
                       str_contains(strtolower($p->sku ?? ''), $searchTerm) ||
                       str_contains(strtolower($p->barcode ?? ''), $searchTerm);
            });
        }

        if ($categoryId) {
            $products = $products->where('category_id', $categoryId);
        }

        if ($stockFilter === 'low') {
            $products = $products->filter(function ($p) {
                return $p->isLowStock();
            });
        } elseif ($stockFilter === 'out') {
            $products = $products->filter(function ($p) {
                return $p->stock_quantity <= 0;
            });
        } elseif ($stockFilter === 'positive') {
            $products = $products->filter(function ($p) {
                return $p->stock_quantity > 0;
            });
        }

        $categories = Category::orderBy('name')->get();

        $itemQuantities = [];
        if (session()->has('reconciliation_items')) {
            foreach (session('reconciliation_items') as $item) {
                $itemQuantities[$item['product_id']] = $item['new_quantity'];
            }
            session()->forget('reconciliation_items');
        }

        $totalProducts = $products->count();
        $totalStockValue = $products->sum(function ($p) {
            return $p->stock_quantity * $p->cost_price;
        });
        $totalRetailValue = $products->sum(function ($p) {
            return $p->stock_quantity * $p->selling_price;
        });

        return view('inventory.reconciliation', compact(
            'products', 'categories', 'categoryId', 'stockFilter', 'search',
            'totalProducts', 'totalStockValue', 'totalRetailValue', 'itemQuantities'
        ));
    }

    public function saveReconciliation(Request $request)
    {
        $request->validate([
            'items' => 'required|array',
            'items.*.product_id' => 'required|exists:products,id',
            'items.*.old_quantity' => 'required|numeric',
            'items.*.new_quantity' => 'required|numeric',
        ]);

        $items = $request->items;
        $updatedCount = 0;

        foreach ($items as $item) {
            $oldQuantity = (float) $item['old_quantity'];
            $newQuantity = (float) $item['new_quantity'];
            $difference = $newQuantity - $oldQuantity;

            if ($difference != 0) {
                $product = Product::findOrFail($item['product_id']);
                $product->update(['stock_quantity' => $newQuantity]);

                InventoryLog::create([
                    'product_id' => $product->id,
                    'user_id' => auth()->id(),
                    'type' => 'reconciliation',
                    'quantity' => abs($difference),
                    'previous_stock' => $oldQuantity,
                    'new_stock' => $newQuantity,
                    'notes' => 'Products Reconciliation: Old qty '.$oldQuantity.' -> New qty '.$newQuantity,
                ]);

                $updatedCount++;
            }
        }

        return redirect()->route('inventory.reconciliation')
            ->with('success', "Stock reconciled successfully for {$updatedCount} product(s).");
    }
}
