<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\PosTable;
use App\Models\BranchFloor;
use App\Models\PosOrder;
use Illuminate\Http\Request;
use App\Http\Controllers\Api\Helpers\RestaurantBranchFilterTrait;

class PosTableController extends Controller
{
    use RestaurantBranchFilterTrait;
    public function index(Request $request)
    {
        $query = PosTable::with('floor');
        
        // Apply restaurant and branch filtering
        $user = $request->user();
        $this->applyRestaurantBranchFilter($query, $user, $request);
        
        // Note: warehouse_id column removed - using branch_id instead

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

        if ($request->has('floor_id') && $request->floor_id) {
            $query->where('floor_id', $request->floor_id);
        }

        // Support pagination
        if ($request->has('page') || $request->has('per_page')) {
            $perPage = $request->input('per_page', 25);
            $tables = $query->orderBy('number')->paginate($perPage);
            return response()->json($tables);
        }

        $tables = $query->orderBy('number')->get();

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

    public function store(Request $request)
    {
        $user = $request->user();
        
        // Allow admin, restaurant_owner, and branch_manager to create tables
        if (!$user || !in_array($user->role, ['admin', 'restaurant_owner', 'branch_manager'])) {
            return response()->json(['message' => 'Unauthorized. Only admins, restaurant owners, and branch managers can create tables.'], 403);
        }
        
        // Get restaurant and branch context
        $context = $this->getRestaurantBranchContext($user, $request);
        
        $branchId = $context['branch_id'] ?? $request->input('branch_id') ?? $user->branch_id ?? null;
        $restaurantId = $context['restaurant_id'] ?? $request->input('restaurant_id') ?? $user->restaurant_id ?? null;
        
        // Ensure branch_id is set for admin and restaurant owner
        if ($user->isAdmin() || $user->isRestaurantOwner()) {
            if (!$branchId) {
                return response()->json(['message' => 'Branch is required. Please select a branch.'], 422);
            }
        }
        
        // For branch manager, use their branch_id
        if ($user->isBranchManager() && !$branchId) {
            $branchId = $user->branch_id;
        }
        
        if (!$branchId) {
            return response()->json(['message' => 'Branch is required. Please ensure you are assigned to a branch.'], 422);
        }
        
        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'number' => [
                'required',
                'string',
                'max:50',
                \Illuminate\Validation\Rule::unique('pos_tables', 'number')->where(function ($query) use ($branchId) {
                    return $query->where('branch_id', $branchId);
                })
            ],
            'capacity' => 'required|integer|min:1',
            'status' => 'required|string|in:available,occupied,reserved',
            'branch_id' => 'nullable|exists:branches,id',
            'floor_id' => 'nullable|exists:branch_floors,id',
            'description' => 'nullable|string',
        ]);

        // Validate floor belongs to branch if floor_id is provided
        if (isset($validated['floor_id']) && $validated['floor_id']) {
            $floor = \App\Models\BranchFloor::find($validated['floor_id']);
            if (!$floor || $floor->branch_id != $branchId) {
                return response()->json(['message' => 'Floor does not belong to the selected branch.'], 422);
            }
        }
        
        // Ensure restaurant_id and branch_id are set
        if ($restaurantId) {
            $validated['restaurant_id'] = $restaurantId;
        }
        if ($branchId) {
            $validated['branch_id'] = $branchId;
        }
        
        // Remove warehouse_id if present (column doesn't exist)
        unset($validated['warehouse_id']);

        $table = PosTable::create($validated);

        return response()->json($table->load('floor'), 201);
    }

    public function show(PosTable $table)
    {
        return response()->json($table->load('floor'));
    }

    public function update(Request $request, PosTable $table)
    {
        $user = $request->user();
        
        // Allow admin, restaurant_owner, and branch_manager to update tables
        if (!$user || !in_array($user->role, ['admin', 'restaurant_owner', 'branch_manager'])) {
            return response()->json(['message' => 'Unauthorized. Only admins, restaurant owners, and branch managers can update tables.'], 403);
        }
        
        // Refresh to ensure latest data
        $table->refresh();
        
        // Check access: branch manager can only update their branch's tables
        if ($user->isBranchManager()) {
            if (!$user->branch_id) {
                return response()->json(['message' => 'Unauthorized. Your account is not assigned to a branch.'], 403);
            }
            $tableBranchId = $table->branch_id ? (int) $table->branch_id : null;
            $userBranchId = (int) $user->branch_id;
            if ($tableBranchId !== null && $tableBranchId !== $userBranchId) {
                return response()->json(['message' => 'Unauthorized. You can only update tables in your branch.'], 403);
            }
        }
        
        // Check access: restaurant owner can only update their restaurant's tables
        if ($user->isRestaurantOwner()) {
            $tableRestaurantId = $table->restaurant_id ? (int) $table->restaurant_id : null;
            $userRestaurantId = $user->restaurant_id ? (int) $user->restaurant_id : null;
            if ($tableRestaurantId !== $userRestaurantId) {
                return response()->json(['message' => 'Unauthorized. You can only update tables in your restaurant.'], 403);
            }
        }
        
        // Determine branch_id for validation
        $branchId = $request->input('branch_id') ?? $table->branch_id;
        
        $validated = $request->validate([
            'name' => 'sometimes|required|string|max:255',
            'number' => [
                'sometimes',
                'required',
                'string',
                'max:50',
                \Illuminate\Validation\Rule::unique('pos_tables', 'number')
                    ->ignore($table->id)
                    ->where(function ($query) use ($branchId) {
                        return $query->where('branch_id', $branchId);
                    })
            ],
            'capacity' => 'sometimes|required|integer|min:1',
            'status' => 'sometimes|required|string|in:available,occupied,reserved',
            'branch_id' => 'sometimes|nullable|exists:branches,id',
            'floor_id' => 'nullable|exists:branch_floors,id',
            'description' => 'nullable|string',
        ]);

        // Validate floor belongs to branch if floor_id is provided
        if (isset($validated['floor_id']) && $validated['floor_id']) {
            $floor = \App\Models\BranchFloor::find($validated['floor_id']);
            if (!$floor || $floor->branch_id != $branchId) {
                return response()->json(['message' => 'Floor does not belong to the selected branch.'], 422);
            }
        }
        
        // If branch_id not provided in update, keep existing
        if (!isset($validated['branch_id'])) {
            $validated['branch_id'] = $table->branch_id;
        }
        
        // Remove warehouse_id if present (column doesn't exist)
        unset($validated['warehouse_id']);

        $table->update($validated);

        return response()->json($table->load('floor'));
    }

    public function destroy(PosTable $table)
    {
        $user = request()->user();
        
        // Allow admin, restaurant_owner, and branch_manager to delete tables
        if (!$user || !in_array($user->role, ['admin', 'restaurant_owner', 'branch_manager'])) {
            return response()->json(['message' => 'Unauthorized. Only admins, restaurant owners, and branch managers can delete tables.'], 403);
        }
        
        // Refresh to ensure latest data
        $table->refresh();
        
        // Check access: branch manager can only delete their branch's tables
        if ($user->isBranchManager()) {
            if (!$user->branch_id) {
                return response()->json(['message' => 'Unauthorized. Your account is not assigned to a branch.'], 403);
            }
            $tableBranchId = $table->branch_id ? (int) $table->branch_id : null;
            $userBranchId = (int) $user->branch_id;
            if ($tableBranchId !== null && $tableBranchId !== $userBranchId) {
                return response()->json(['message' => 'Unauthorized. You can only delete tables in your branch.'], 403);
            }
        }
        
        // Check access: restaurant owner can only delete their restaurant's tables
        if ($user->isRestaurantOwner()) {
            $tableRestaurantId = $table->restaurant_id ? (int) $table->restaurant_id : null;
            $userRestaurantId = $user->restaurant_id ? (int) $user->restaurant_id : null;
            if ($tableRestaurantId !== $userRestaurantId) {
                return response()->json(['message' => 'Unauthorized. You can only delete tables in your restaurant.'], 403);
            }
        }
        
        $table->delete();

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

    /**
     * Get tables grouped by floors for dashboard view
     */
    public function dashboard(Request $request)
    {
        $user = $request->user();
        
        // Get branch_id from request or user context
        $branchId = $request->input('branch_id') ?? $user->branch_id ?? null;
        
        if (!$branchId) {
            return response()->json(['message' => 'Branch is required.'], 422);
        }

        // Verify access
        if ($user->isBranchManager() && $user->branch_id != $branchId) {
            return response()->json(['message' => 'Unauthorized. You can only view tables in your branch.'], 403);
        }

        if ($user->isRestaurantOwner()) {
            $branch = \App\Models\Branch::find($branchId);
            if (!$branch || $branch->restaurant_id != $user->restaurant_id) {
                return response()->json(['message' => 'Unauthorized. Branch does not belong to your restaurant.'], 403);
            }
        }

        // Get all floors for this branch (including inactive ones for display)
        $floors = BranchFloor::where('branch_id', $branchId)
            ->orderBy('display_order')
            ->orderBy('name')
            ->get();

        // Get all tables for this branch (including soft-deleted for reference)
        $tables = PosTable::where('branch_id', $branchId)
            ->with('floor')
            ->get();

        // Get active orders (not paid, not cancelled, not deleted) for this branch
        // Eager load tables relationship to check which tables are occupied
        $activeOrders = PosOrder::where('branch_id', $branchId)
            ->whereNull('deleted_at')
            ->where('status', '!=', 'paid')
            ->where('status', '!=', 'cancelled')
            ->with('tables')
            ->get();

        // Get table IDs that are actually booked/occupied from orders
        $occupiedTableIds = collect();
        foreach ($activeOrders as $order) {
            // Check single table relationship
            if ($order->table_id) {
                $occupiedTableIds->push($order->table_id);
            }
            // Check many-to-many table relationship
            if ($order->tables && $order->tables->count() > 0) {
                foreach ($order->tables as $table) {
                    $occupiedTableIds->push($table->id);
                }
            }
        }
        $occupiedTableIds = $occupiedTableIds->unique()->values();

        // Group tables by floor and update status based on orders
        // Note: We return ALL tables, filtering is done on frontend if needed
        $floorsWithTables = $floors->map(function($floor) use ($tables, $occupiedTableIds) {
            $floorTables = $tables->where('floor_id', $floor->id)->values();
            
            // Update table status based on active orders
            $updatedTables = $floorTables->map(function($table) use ($occupiedTableIds) {
                $actualStatus = $table->status;
                // If table has an active order, mark it as occupied/booked
                if ($occupiedTableIds->contains($table->id)) {
                    $actualStatus = 'occupied';
                }
                
                return [
                    'id' => $table->id,
                    'name' => $table->name,
                    'number' => $table->number,
                    'capacity' => $table->capacity,
                    'status' => $actualStatus,
                    'original_status' => $table->status, // Keep original for reference
                    'description' => $table->description,
                ];
            });
            
            // Calculate stats based on actual status from orders
            $stats = [
                'all' => $updatedTables->count(),
                'available' => $updatedTables->where('status', 'available')->count(),
                'reserved' => $updatedTables->where('status', 'reserved')->count(),
                'booked' => $updatedTables->where('status', 'occupied')->count(),
            ];

            return [
                'id' => $floor->id,
                'name' => $floor->name,
                'code' => $floor->code,
                'display_order' => $floor->display_order,
                'stats' => $stats,
                'tables' => $updatedTables, // Return ALL tables for this floor
            ];
        });

        // Tables without floor
        $tablesWithoutFloor = $tables->whereNull('floor_id')->values();
        if ($tablesWithoutFloor->count() > 0) {
            // Update table status based on active orders
            $updatedTablesWithoutFloor = $tablesWithoutFloor->map(function($table) use ($occupiedTableIds) {
                $actualStatus = $table->status;
                // If table has an active order, mark it as occupied/booked
                if ($occupiedTableIds->contains($table->id)) {
                    $actualStatus = 'occupied';
                }
                
                return [
                    'id' => $table->id,
                    'name' => $table->name,
                    'number' => $table->number,
                    'capacity' => $table->capacity,
                    'status' => $actualStatus,
                    'original_status' => $table->status,
                    'description' => $table->description,
                ];
            });
            
            // Calculate stats from all tables
            $stats = [
                'all' => $updatedTablesWithoutFloor->count(),
                'available' => $updatedTablesWithoutFloor->where('status', 'available')->count(),
                'reserved' => $updatedTablesWithoutFloor->where('status', 'reserved')->count(),
                'booked' => $updatedTablesWithoutFloor->where('status', 'occupied')->count(),
            ];

            $floorsWithTables->push([
                'id' => null,
                'name' => 'No Floor',
                'code' => null,
                'display_order' => 9999,
                'stats' => $stats,
                'tables' => $updatedTablesWithoutFloor, // Return ALL tables without floor
            ]);
        }

        // Calculate overall stats from all floors
        $overallStats = [
            'all' => 0,
            'available' => 0,
            'reserved' => 0,
            'booked' => 0,
        ];
        
        foreach ($floorsWithTables as $floor) {
            $overallStats['all'] += $floor['stats']['all'];
            $overallStats['available'] += $floor['stats']['available'];
            $overallStats['reserved'] += $floor['stats']['reserved'];
            $overallStats['booked'] += $floor['stats']['booked'];
        }

        // Convert to array to ensure proper JSON encoding
        $floorsArray = $floorsWithTables->map(function($floor) {
            return [
                'id' => $floor['id'],
                'name' => $floor['name'],
                'code' => $floor['code'],
                'display_order' => $floor['display_order'],
                'stats' => $floor['stats'],
                'tables' => array_values($floor['tables']->toArray()), // Ensure tables is a proper array
            ];
        })->values()->toArray();

        return response()->json([
            'floors' => $floorsArray,
            'stats' => $overallStats,
        ]);
    }
}
