<?php

namespace App\Http\Controllers;

use App\Models\InventoryItem;
use App\Models\StockMovement;
use App\Services\CacheService;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\DB;

class InventoryController extends Controller
{
    public function index(Request $request): JsonResponse
    {
        $params = [
            'category' => $request->get('category'),
            'stock_status' => $request->get('stock_status'),
            'search' => $request->get('search'),
            'page' => $request->get('page', 1)
        ];

        $cacheKey = CacheService::key(
            'inventory_items',
            $request->user()->restaurant_id,
            $request->user()->branch_id,
            array_filter($params)
        );

        // For paginated results, we'll cache for shorter time
        $items = CacheService::remember($cacheKey, 180, function () use ($request) { // 3 minutes
            $query = InventoryItem::with(['branch', 'stockMovements' => function ($q) {
                $q->latest()->limit(5);
            }])->where('restaurant_id', $request->user()->restaurant_id);

            // Filter by branch if user is not admin
            if ($request->user()->branch_id) {
                $query->where(function ($q) use ($request) {
                    $q->where('branch_id', $request->user()->branch_id)
                      ->orWhereNull('branch_id'); // Global items
                });
            }

            // Filter by category
            if ($request->filled('category')) {
                $query->where('category', $request->category);
            }

            // Filter by stock status
            if ($request->filled('stock_status')) {
                switch ($request->stock_status) {
                    case 'low':
                        $query->lowStock();
                        break;
                    case 'out':
                        $query->outOfStock();
                        break;
                    case 'expiring':
                        $query->expiringSoon();
                        break;
                    case 'expired':
                        $query->expired();
                        break;
                }
            }

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

            return $query->orderBy('name')->paginate(2000);
        });

        // Transform items to include computed attributes
        $transformedItems = $items->getCollection()->map(function ($item) {
            return [
                'id' => $item->id,
                'name' => $item->name,
                'sku' => $item->sku,
                'description' => $item->description,
                'category' => $item->category,
                'category_display' => $item->category_display,
                'unit' => $item->unit,
                'current_stock' => $item->current_stock,
                'minimum_stock' => $item->minimum_stock,
                'maximum_stock' => $item->maximum_stock,
                'cost_per_unit' => $item->cost_per_unit,
                'selling_price' => $item->selling_price,
                'supplier' => $item->supplier,
                'supplier_contact' => $item->supplier_contact,
                'expiry_date' => $item->expiry_date?->format('Y-m-d'),
                'track_expiry' => $item->track_expiry,
                'is_active' => $item->is_active,
                'branch_id' => $item->branch_id,
                'branch' => $item->branch,
                'stock_value' => $item->stock_value,
                'is_low_stock' => $item->is_low_stock,
                'is_out_of_stock' => $item->is_out_of_stock,
                'is_expiring_soon' => $item->is_expiring_soon,
                'is_expired' => $item->is_expired,
                'status' => $item->is_expired ? 'expired' : 
                           ($item->is_expiring_soon ? 'expiring_soon' : 
                           ($item->is_out_of_stock ? 'out_of_stock' : 
                           ($item->is_low_stock ? 'low_stock' : 'in_stock'))),
                'status_display' => $item->is_expired ? 'Expired' : 
                                  ($item->is_expiring_soon ? 'Expiring Soon' : 
                                  ($item->is_out_of_stock ? 'Out of Stock' : 
                                  ($item->is_low_stock ? 'Low Stock' : 'In Stock'))),
                'formatted_cost' => 'KES ' . number_format($item->cost_per_unit, 2) . '/' . $item->unit,
                'formatted_total_value' => 'KES ' . number_format($item->stock_value, 2),
                'stock_percentage' => $item->maximum_stock > 0 ? 
                    round(($item->current_stock / $item->maximum_stock) * 100, 1) : null,
                'days_until_expiry' => $item->track_expiry && $item->expiry_date ? 
                    $item->expiry_date->diffInDays(now(), false) : null,
                'created_at' => $item->created_at,
                'updated_at' => $item->updated_at,
            ];
        });

        return response()->json([
            'items' => $transformedItems,
            'pagination' => [
                'current_page' => $items->currentPage(),
                'last_page' => $items->lastPage(),
                'per_page' => $items->perPage(),
                'total' => $items->total(),
            ],
        ]);
    }

    public function store(Request $request): JsonResponse
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'sku' => 'required|string|unique:inventory_items,sku',
            'description' => 'nullable|string',
            'category' => 'required|in:ingredient,beverage,packaging,cleaning,other',
            'unit' => 'required|string|max:50',
            'current_stock' => 'required|numeric|min:0',
            'minimum_stock' => 'required|numeric|min:0',
            'maximum_stock' => 'nullable|numeric|min:0',
            'cost_per_unit' => 'required|numeric|min:0',
            'selling_price' => 'nullable|numeric|min:0',
            'supplier' => 'nullable|string|max:255',
            'supplier_contact' => 'nullable|string|max:255',
            'expiry_date' => 'nullable|date|after:today',
            'track_expiry' => 'boolean',
            'branch_id' => [
                'nullable',
                Rule::exists('branches', 'id')->where('restaurant_id', $request->user()->restaurant_id),
            ],
        ]);

        $item = InventoryItem::create([
            'restaurant_id' => $request->user()->restaurant_id,
            'branch_id' => $request->branch_id,
            'name' => $request->name,
            'sku' => $request->sku,
            'description' => $request->description,
            'category' => $request->category,
            'unit' => $request->unit,
            'current_stock' => $request->current_stock,
            'minimum_stock' => $request->minimum_stock,
            'maximum_stock' => $request->maximum_stock,
            'cost_per_unit' => $request->cost_per_unit,
            'selling_price' => $request->selling_price,
            'supplier' => $request->supplier,
            'supplier_contact' => $request->supplier_contact,
            'expiry_date' => $request->expiry_date,
            'track_expiry' => $request->track_expiry ?? false,
        ]);

        // Create initial stock movement
        if ($request->current_stock > 0) {
            $item->adjustStock(
                $request->current_stock,
                'adjustment',
                'Initial stock',
                'Initial inventory setup',
                $request->user()
            );
        }

        return response()->json([
            'message' => 'Inventory item created successfully',
            'item' => $item->load('branch'),
        ], 201);
    }

    public function show(InventoryItem $item): JsonResponse
    {
        $item->load(['branch', 'stockMovements.user', 'menuItems']);

        return response()->json($item);
    }

    public function update(Request $request, InventoryItem $item): JsonResponse
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'sku' => ['required', 'string', Rule::unique('inventory_items')->ignore($item->id)],
            'description' => 'nullable|string',
            'category' => 'required|in:ingredient,beverage,packaging,cleaning,other',
            'unit' => 'required|string|max:50',
            'minimum_stock' => 'required|numeric|min:0',
            'maximum_stock' => 'nullable|numeric|min:0',
            'cost_per_unit' => 'required|numeric|min:0',
            'selling_price' => 'nullable|numeric|min:0',
            'supplier' => 'nullable|string|max:255',
            'supplier_contact' => 'nullable|string|max:255',
            'expiry_date' => 'nullable|date|after:today',
            'track_expiry' => 'boolean',
        ]);

        $item->update($request->only([
            'name', 'sku', 'description', 'category', 'unit',
            'minimum_stock', 'maximum_stock', 'cost_per_unit',
            'selling_price', 'supplier', 'supplier_contact',
            'expiry_date', 'track_expiry'
        ]));

        return response()->json([
            'message' => 'Inventory item updated successfully',
            'item' => $item->load('branch'),
        ]);
    }

    public function adjustStock(Request $request, InventoryItem $item): JsonResponse
    {
        $request->validate([
            'quantity' => 'required|numeric|not_in:0',
            'type' => 'required|in:purchase,sale,adjustment,waste,transfer',
            'notes' => 'nullable|string|max:500',
            'reference' => 'nullable|string|max:255',
        ]);

        $item->adjustStock(
            $request->quantity,
            $request->type,
            $request->reference,
            $request->notes,
            $request->user()
        );

        return response()->json([
            'message' => 'Stock adjusted successfully',
            'item' => $item->fresh(),
        ]);
    }

    public function stockMovements(Request $request, InventoryItem $item): JsonResponse
    {
        $movements = $item->stockMovements()
            ->with('user')
            ->orderBy('created_at', 'desc')
            ->paginate(2000);

        return response()->json([
            'movements' => $movements->items(),
            'pagination' => [
                'current_page' => $movements->currentPage(),
                'last_page' => $movements->lastPage(),
                'per_page' => $movements->perPage(),
                'total' => $movements->total(),
            ],
        ]);
    }

    public function alerts(Request $request): JsonResponse
    {
        $restaurantId = $request->user()->restaurant_id;
        $branchId = $request->user()->branch_id;

        $query = InventoryItem::where('restaurant_id', $restaurantId);

        if ($branchId) {
            $query->where(function ($q) use ($branchId) {
                $q->where('branch_id', $branchId)->orWhereNull('branch_id');
            });
        }

        $alerts = [
            'low_stock' => $query->clone()->lowStock()->with('branch')->get(),
            'out_of_stock' => $query->clone()->outOfStock()->with('branch')->get(),
            'expiring_soon' => $query->clone()->expiringSoon()->with('branch')->get(),
            'expired' => $query->clone()->expired()->with('branch')->get(),
        ];

        return response()->json($alerts);
    }

    public function summary(Request $request): JsonResponse
    {
        $cacheKey = CacheService::key(
            'inventory_summary',
            $request->user()->restaurant_id,
            $request->user()->branch_id
        );

        $summary = CacheService::remember($cacheKey, CacheService::INVENTORY_SUMMARY_TTL, function () use ($request) {
            $restaurantId = $request->user()->restaurant_id;
            $branchId = $request->user()->branch_id;

            $query = InventoryItem::where('restaurant_id', $restaurantId);

            if ($branchId) {
                $query->where(function ($q) use ($branchId) {
                    $q->where('branch_id', $branchId)->orWhereNull('branch_id');
                });
            }

            $totalValue = $query->clone()->sum(DB::raw('current_stock * cost_per_unit'));

            return [
                'total_items' => $query->clone()->count(),
                'low_stock_items' => $query->clone()->lowStock()->count(),
                'out_of_stock_items' => $query->clone()->outOfStock()->count(),
                'expiring_items' => $query->clone()->expiringSoon()->count(),
                'expired_items' => $query->clone()->expired()->count(),
                'total_value' => $totalValue,
                'formatted_total_value' => 'KES ' . number_format($totalValue, 2),
                'categories' => $query->clone()
                    ->selectRaw('category, COUNT(*) as count, SUM(current_stock * cost_per_unit) as value')
                    ->groupBy('category')
                    ->get(),
            ];
        });

        return response()->json($summary, 200, CacheService::getHttpHeaders('inventory'));
    }

    public function updatePrice(Request $request, InventoryItem $item): JsonResponse
    {
        $request->validate([
            'selling_price' => 'required|numeric|min:0',
        ]);

        $item->update([
            'selling_price' => $request->selling_price,
        ]);

        // Clear cache
        CacheService::clearInventoryCache($item->restaurant_id, $item->branch_id);

        return response()->json([
            'message' => 'Price updated successfully',
            'item' => $item->fresh()->load('branch'),
        ]);
    }

    public function destroy(InventoryItem $item): JsonResponse
    {
        // Check if item is used in any menu items
        if ($item->menuItems()->count() > 0) {
            return response()->json([
                'error' => 'Cannot delete inventory item that is used in menu items'
            ], 400);
        }

        // Clear cache before deletion
        CacheService::clearInventoryCache($item->restaurant_id, $item->branch_id);

        $item->delete();

        return response()->json(['message' => 'Inventory item deleted successfully']);
    }

}