<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\StockOut;
use App\Models\Inventory;
use App\Models\Branch;
use App\Models\Agent;
use App\Services\InventoryTransactionService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class InventoryTransferController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth:sanctum');
    }

    public function index(Request $request)
    {
        $query = StockOut::with(['inventory.item', 'inventory.category', 'branch', 'agent', 'transferredBy', 'returns'])
            ->where('is_return', false); // Only show transfers, not returns

        $user = $request->user();

        // Filter by restaurant
        if ($user->isAdmin()) {
            // Admin: filter by selected restaurant
            if ($request->has('restaurant_id') && $request->restaurant_id) {
                $query->where('restaurant_id', $request->restaurant_id);
            } else {
                // Admin must select restaurant - return empty if not selected
                return response()->json([
                    'data' => [],
                    'current_page' => 1,
                    'last_page' => 1,
                    'per_page' => $request->get('per_page', 50),
                    'total' => 0,
                ]);
            }
        } elseif ($user->isInventoryManager() && $user->restaurant_id) {
            // Inventory manager: filter by their restaurant
            $query->where('restaurant_id', $user->restaurant_id);
        } elseif ($user->isBranchManager() && $user->branch_id) {
            // Branch manager: get restaurant_id from their branch and filter
            $branch = Branch::find($user->branch_id);
            if ($branch && $branch->restaurant_id) {
                $query->where('restaurant_id', $branch->restaurant_id);
                // Also filter by their branch
                $query->where('branch_id', $user->branch_id);
            } else {
                // No branch or restaurant assigned
                return response()->json([
                    'data' => [],
                    'current_page' => 1,
                    'last_page' => 1,
                    'per_page' => $request->get('per_page', 50),
                    'total' => 0,
                ]);
            }
        } elseif ($user->isRestaurantOwner() && $user->restaurant_id) {
            // Restaurant owner: filter by their restaurant
            $query->where('restaurant_id', $user->restaurant_id);
        }

        // Filter by branch_id (additional filter for admin and inventory_manager)
        if ($request->has('branch_id') && $request->branch_id) {
            $query->where('branch_id', $request->branch_id);
        } elseif (!$user->isAdmin() && !$user->isBranchManager() && !$user->isInventoryManager() && $user->restaurant_id) {
            // For restaurant owners (not branch managers or inventory managers), show all branches of their restaurant
            $branchIds = Branch::where('restaurant_id', $user->restaurant_id)->pluck('id');
            if ($branchIds->isNotEmpty()) {
                $query->whereIn('branch_id', $branchIds);
            } else {
                // No branches found
                return response()->json([
                    'data' => [],
                    'current_page' => 1,
                    'last_page' => 1,
                    'per_page' => $request->get('per_page', 50),
                    'total' => 0,
                ]);
            }
        }

        // Filter by inventory
        if ($request->has('inventory_id')) {
            $query->where('inventory_id', $request->inventory_id);
        }

        // Filter by category
        if ($request->has('category_id') && $request->category_id) {
            $query->whereHas('inventory', function ($q) use ($request) {
                $q->where('category_id', $request->category_id);
            });
        }

        // Search by item name or category
        if ($request->has('search') && $request->search) {
            $search = $request->search;
            $query->whereHas('inventory', function ($q) use ($search) {
                $q->where('item_name', 'like', '%' . $search . '%')
                    ->orWhere('category', 'like', '%' . $search . '%');
            });
        }

        // Filter by date range
        if ($request->has('date_from')) {
            $query->whereDate('created_at', '>=', $request->date_from);
        }
        if ($request->has('date_to')) {
            $query->whereDate('created_at', '<=', $request->date_to);
        }

        $transfers = $query->orderBy('created_at', 'desc')->paginate($request->get('per_page', 50));

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

    public function store(Request $request)
    {
        $validated = $request->validate([
            'inventory_id' => 'required|exists:inventories,id',
            'branch_id' => 'required|exists:branches,id',
            'agent_id' => 'nullable|exists:agents,id',
            'quantity_transferred' => 'required|numeric|min:0.01',
            'notes' => 'nullable|string',
        ]);

        $user = $request->user();

        DB::beginTransaction();
        try {
            $inventory = Inventory::findOrFail($validated['inventory_id']);

            // Verify branch access
            if (!$user->isAdmin() && !$user->isInventoryManager()) {
                if ($user->branch_id && $user->branch_id != $validated['branch_id']) {
                    return response()->json([
                        'error' => 'You do not have access to this branch'
                    ], 403);
                }
            }
            
            // For inventory manager, verify branch belongs to their restaurant
            if ($user->isInventoryManager()) {
                $branch = Branch::findOrFail($validated['branch_id']);
                if ($branch->restaurant_id != $user->restaurant_id) {
                    return response()->json([
                        'error' => 'You do not have access to this branch'
                    ], 403);
                }
            }

            // Check available quantity from inventories table
            $availableQuantity = Inventory::getCurrentStockForBranch($inventory->item_id, $inventory->branch_id);
            if ($availableQuantity < $validated['quantity_transferred']) {
                return response()->json([
                    'error' => 'Insufficient stock available. Available: ' . $availableQuantity
                ], 400);
            }

            $data = [
                'inventory_id' => $validated['inventory_id'],
                'branch_id' => $validated['branch_id'],
                'agent_id' => $validated['agent_id'] ?? null,
                'quantity_transferred' => $validated['quantity_transferred'],
                'unit_price' => $inventory->unit_price,
                'transferred_by' => $user->id,
                'notes' => $validated['notes'] ?? null,
                'restaurant_id' => $inventory->restaurant_id,
            ];

            $transfer = StockOut::create($data);

            // Create "Out" inventory record at source branch
            $outInventory = Inventory::create([
                'item_id' => $inventory->item_id,
                'item_name' => $inventory->item_name,
                'category_id' => $inventory->category_id,
                'category' => $inventory->category,
                'item_unit' => $inventory->item_unit,
                'unit_price' => $inventory->unit_price,
                'quantity' => $validated['quantity_transferred'],
                'branch_id' => $inventory->branch_id,
                'restaurant_id' => $inventory->restaurant_id,
                'created_by' => $user->id,
                'transaction_type' => 'out',
                'reference_type' => 'transfer',
                'reference_id' => $transfer->id,
                'last_transaction_at' => now(),
            ]);

            // Create "In" inventory record at destination branch
            $destinationBranch = Branch::findOrFail($validated['branch_id']);
            $inInventory = Inventory::create([
                'item_id' => $inventory->item_id,
                'item_name' => $inventory->item_name,
                'category_id' => $inventory->category_id,
                'category' => $inventory->category,
                'item_unit' => $inventory->item_unit,
                'unit_price' => $inventory->unit_price,
                'quantity' => $validated['quantity_transferred'],
                'branch_id' => $validated['branch_id'],
                'restaurant_id' => $inventory->restaurant_id,
                'created_by' => $user->id,
                'transaction_type' => 'in',
                'reference_type' => 'transfer',
                'reference_id' => $transfer->id,
                'last_transaction_at' => now(),
            ]);

            // Create minimal transaction records for audit
            InventoryTransactionService::createOutTransaction($outInventory, $validated['quantity_transferred'], [
                'reference_type' => 'transfer',
                'reference_id' => $transfer->id,
                'branch_id' => $inventory->branch_id,
                'restaurant_id' => $inventory->restaurant_id,
                'created_by' => $user->id,
            ]);
            
            InventoryTransactionService::createInTransaction($inInventory, $validated['quantity_transferred'], [
                'reference_type' => 'transfer',
                'reference_id' => $transfer->id,
                'branch_id' => $validated['branch_id'],
                'restaurant_id' => $inventory->restaurant_id,
                'created_by' => $user->id,
            ]);

            DB::commit();

            $transfer->load(['inventory.item', 'inventory.category', 'branch', 'agent', 'transferredBy']);

            return response()->json($transfer, 201);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'error' => 'An error occurred: ' . $e->getMessage()
            ], 500);
        }
    }

    public function show(StockOut $stockOut)
    {
        $user = request()->user();
        
        // Verify access
        if (!$user->isAdmin()) {
            $stockOutRestaurantId = (int) $stockOut->restaurant_id;
            
            if ($user->isInventoryManager() && $user->restaurant_id) {
                $userRestaurantId = (int) $user->restaurant_id;
                if ($stockOutRestaurantId !== $userRestaurantId) {
                    return response()->json(['error' => 'Unauthorized'], 403);
                }
            } elseif ($user->isRestaurantOwner() && $user->restaurant_id) {
                $userRestaurantId = (int) $user->restaurant_id;
                if ($stockOutRestaurantId !== $userRestaurantId) {
                    return response()->json(['error' => 'Unauthorized'], 403);
                }
            } elseif ($user->isBranchManager() && $user->branch_id) {
                $branch = Branch::find($user->branch_id);
                if (!$branch || (int) $branch->restaurant_id !== $stockOutRestaurantId) {
                    return response()->json(['error' => 'Unauthorized'], 403);
                }
            } else {
                return response()->json(['error' => 'Unauthorized'], 403);
            }
        }
        
        $stockOut->load(['inventory.item', 'inventory.category', 'branch', 'agent', 'transferredBy']);
        return response()->json($stockOut);
    }

    public function getAvailableQuantity(Request $request)
    {
        $request->validate([
            'inventory_id' => 'required|exists:inventories,id',
        ]);

        $inventory = Inventory::findOrFail($request->inventory_id);
        
        // Calculate available quantity from inventories table
        $available = Inventory::getCurrentStockForBranch($inventory->item_id, $inventory->branch_id);
        
        return response()->json([
            'available' => $available,
            'unit_price' => $inventory->unit_price,
            'item_name' => $inventory->item_name,
        ]);
    }

    /**
     * Get unique inventory items for a branch with calculated available quantities
     */
    public function getBranchInventoryItems(Request $request)
    {
        $request->validate([
            'branch_id' => 'required|exists:branches,id',
        ]);

        $user = $request->user();
        $branchId = $request->branch_id;
        $branch = Branch::findOrFail($branchId);

        // Check access
        if ($user->isAdmin()) {
            // Admin can access any branch
        } elseif ($user->isInventoryManager() && $user->restaurant_id) {
            // Inventory manager: verify branch belongs to their restaurant
            if ($branch->restaurant_id != $user->restaurant_id) {
                return response()->json(['error' => 'You do not have access to this branch'], 403);
            }
        } elseif ($user->isBranchManager() && $user->branch_id) {
            // Branch manager: can only access their own branch
            if ($branchId != $user->branch_id) {
                return response()->json(['error' => 'You can only access your own branch'], 403);
            }
        } elseif ($user->restaurant_id) {
            // Restaurant owner: verify branch belongs to their restaurant
            if ($branch->restaurant_id != $user->restaurant_id) {
                return response()->json(['error' => 'You do not have access to this branch'], 403);
            }
        } else {
            return response()->json(['error' => 'Unauthorized'], 403);
        }

        // Get unique items for this branch with their latest inventory record
        $items = Inventory::where('branch_id', $branchId)
            ->select('item_id', 'item_name', 'category_id', 'category', 'item_unit', 'unit_price')
            ->groupBy('item_id', 'item_name', 'category_id', 'category', 'item_unit', 'unit_price')
            ->get();

        // Calculate available quantity for each item and get a representative inventory ID
        $itemsWithStock = $items->map(function ($item) use ($branchId) {
            $availableQuantity = Inventory::getCurrentStockForBranch($item->item_id, $branchId);
            
            // Get the latest inventory record for this item at this branch (for the inventory_id)
            $latestInventory = Inventory::where('item_id', $item->item_id)
                ->where('branch_id', $branchId)
                ->orderBy('created_at', 'desc')
                ->first();
            
            return [
                'id' => $latestInventory ? $latestInventory->id : $item->item_id, // Use actual inventory ID
                'inventory_id' => $latestInventory ? $latestInventory->id : null,
                'item_id' => $item->item_id,
                'item_name' => $item->item_name,
                'category_id' => $item->category_id,
                'category' => $item->category,
                'item_unit' => $item->item_unit,
                'unit_price' => $item->unit_price,
                'available_quantity' => max(0, $availableQuantity), // Ensure it's never negative
            ];
        })->filter(function ($item) {
            // Show all items, even with 0 quantity (as per user request: show 0 if quantity is 0 or less)
            return true;
        })->values();

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

    public function getAgents(Request $request)
    {
        $request->validate([
            'branch_id' => 'required|exists:branches,id',
        ]);

        $agents = Agent::where('branch_id', $request->branch_id)
            ->where('status', 'active')
            ->get(['id', 'name', 'phone']);

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

    /**
     * Get returnable items for an inventory in a branch
     * Returns list of transfers that can be returned
     */
    public function getReturnableItems(Request $request)
    {
        $request->validate([
            'inventory_id' => 'required|exists:inventories,id',
            'branch_id' => 'required|exists:branches,id',
        ]);

        $user = $request->user();

        // Verify branch access
        if (!$user->isAdmin()) {
            if ($user->branch_id && $user->branch_id != $request->branch_id) {
                return response()->json(['error' => 'You do not have access to this branch'], 403);
            }
        }

        // Get all transfers for this inventory to this branch (non-return transfers)
        $transfers = StockOut::with(['inventory', 'branch', 'transferredBy'])
            ->where('inventory_id', $request->inventory_id)
            ->where('branch_id', $request->branch_id)
            ->where('is_return', false)
            ->orderBy('created_at', 'desc')
            ->get();

        // Calculate returnable quantity for each transfer
        $returnableItems = $transfers->map(function ($transfer) {
            $alreadyReturned = StockOut::where('original_stock_out_id', $transfer->id)
                ->where('is_return', true)
                ->sum('quantity_transferred');

            $returnableQuantity = $transfer->quantity_transferred - $alreadyReturned;

            return [
                'id' => $transfer->id,
                'transfer_date' => $transfer->created_at->format('Y-m-d H:i:s'),
                'quantity_transferred' => $transfer->quantity_transferred,
                'already_returned' => $alreadyReturned,
                'returnable_quantity' => max(0, $returnableQuantity),
                'unit_price' => $transfer->unit_price,
                'transferred_by' => $transfer->transferredBy ? $transfer->transferredBy->name : null,
                'notes' => $transfer->notes,
            ];
        })->filter(function ($item) {
            return $item['returnable_quantity'] > 0; // Only show items that can still be returned
        })->values();

        return response()->json(['data' => $returnableItems]);
    }
}

