<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Locker;
use App\Models\Client;
use App\Models\LockerGroup;
use App\Models\LockerRegistrationItem;
use Carbon\Carbon;

class LockerController extends Controller
{
    /**
     * Display a listing of all lockers.
     */
    public function index(Request $request)
    {
        // Get locker groups from database with numeric sorting
        $lockerGroups = LockerGroup::orderByRaw('CAST(SUBSTRING(name, 7) AS UNSIGNED)')->get();

        // Get counts for all 5 statuses
        $stats = [
            'total' => Locker::count(),
            'available' => Locker::available()->count(),
            'reserved' => Locker::reserved()->count(),
            'occupied' => Locker::occupied()->count(),
            'maintenance' => Locker::maintenance()->count(),
            'blocked' => Locker::blocked()->count(),
        ];

        return view('lockers.index', compact('lockerGroups', 'stats'));
    }

    /**
     * Display available lockers.
     */
    public function available(Request $request)
    {
        // Get locker groups with counts
        $lockerGroups = LockerGroup::withCount(['lockers' => function ($query) {
            $query->where('status', 'Available');
        }])->get()->sortBy(function ($group) {
            // Extract numeric part for proper sorting
            preg_match('/(\d+)/', $group->name, $matches);
            return isset($matches[1]) ? (int)$matches[1] : $group->name;
        })->values();

        return view('lockers.available', compact('lockerGroups'));
    }

    /**
     * Show the form for creating a new locker.
     */
    public function create()
    {
        $customers = Client::orderBy('name')->get();

        return view('lockers.create', compact('customers'));
    }

    /**
     * Store a newly created locker in storage.
     */
    public function store(Request $request)
    {
        $validated = $request->validate([
            'locker_number' => 'required|string|max:255|unique:lockers,locker_number',
            'locker_size' => 'required|in:small,medium,large,Extra large',
            'locker_type' => 'required|in:Default,Fancy',
            'status' => 'required|in:available,reserved,occupied,maintenance,blocked',
            'customer_id' => 'nullable|exists:clients,id',
        ]);

        // If status is occupied, customer_id is required
        if ($validated['status'] === 'occupied' && empty($validated['customer_id'])) {
            return back()->withInput()->withErrors([
                'customer_id' => 'Customer is required when locker status is occupied.'
            ]);
        }

        Locker::create($validated);

        return redirect()->route('lockers.index')
            ->with('success', 'Locker created successfully.');
    }

    /**
     * Display the specified locker.
     */
    public function show(Locker $locker)
    {
        $locker->load(['customer', 'lockerRegistrations']);

        return view('lockers.show', compact('locker'));
    }

    /**
     * Show the form for editing the specified locker.
     */
    public function edit(Locker $locker)
    {
        $customers = Client::orderBy('name')->get();

        return view('lockers.edit', compact('locker', 'customers'));
    }

    /**
     * Update the specified locker in storage.
     */
    public function update(Request $request, Locker $locker)
    {
        $validated = $request->validate([
            'locker_number' => 'required|string|max:255|unique:lockers,locker_number,' . $locker->id,
            'locker_size' => 'required|in:small,medium,large,Extra_large',
            'locker_type' => 'required|string|max:255',
            'status' => 'required|in:available,occupied,maintenance',
            'customer_id' => 'nullable|exists:clients,id',
        ]);

        // If status is occupied, customer_id is required
        if ($validated['status'] === 'occupied' && empty($validated['customer_id'])) {
            return back()->withInput()->withErrors([
                'customer_id' => 'Customer is required when locker status is occupied.'
            ]);
        }

        // If status is changing to available, clear customer_id
        if ($validated['status'] === 'available') {
            $validated['customer_id'] = null;
        }

        $locker->update($validated);

        return redirect()->route('lockers.index')
            ->with('success', 'Locker updated successfully.');
    }

    /**
     * Remove the specified locker from storage.
     */
    public function destroy(Locker $locker)
    {
        // Check if locker has active registrations
        if ($locker->lockerRegistrations()->where('status', 'Active')->exists()) {
            return back()->with('error', 'Cannot delete locker with active registrations.');
        }

        $locker->delete();

        return redirect()->route('lockers.index')
            ->with('success', 'Locker deleted successfully.');
    }

    /**
     * Assign a locker to a customer.
     */
    public function assign(Request $request, Locker $locker)
    {
        $validated = $request->validate([
            'customer_id' => 'required|exists:clients,id',
            'notes' => 'nullable|string',
        ]);

        // Update locker status and customer
        $locker->update([
            'status' => 'occupied',
            'customer_id' => $validated['customer_id'],
        ]);

        return redirect()->route('lockers.index')
            ->with('success', 'Locker assigned successfully.');
    }

    /**
     * Release a locker from customer.
     */
    public function release(Locker $locker)
    {
        $locker->update([
            'status' => 'available',
            'customer_id' => null,
        ]);

        return redirect()->route('lockers.index')
            ->with('success', 'Locker released successfully.');
    }

    /**
     * API endpoint to get next locker number.
     */
    public function getNextNumber()
    {
        try {
            // Get the last locker number
            $lastLocker = Locker::orderBy('id', 'desc')->first();

            if ($lastLocker && $lastLocker->locker_number) {
                // Extract numeric part and increment
                $lastNumber = $lastLocker->locker_number;

                // Handle MSB prefix pattern
                if (preg_match('/MSB(\d+)/', $lastNumber, $matches)) {
                    $nextNumber = 'MSB' . str_pad($matches[1] + 1, 3, '0', STR_PAD_LEFT);
                } else {
                    // Fallback if pattern doesn't match
                    $nextNumber = 'MSB001';
                }
            } else {
                // No lockers exist, start with MSB001
                $nextNumber = 'MSB001';
            }

            return response()->json([
                'next_number' => $nextNumber,
                'last_number' => $lastLocker ? $lastLocker->locker_number : null
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'next_number' => 'MSB001',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Get lockers for a specific group.
     */
    public function getLockersByGroup(Request $request, $groupId)
    {
        $group = LockerGroup::findOrFail($groupId);

        $lockers = Locker::where('locker_group_id', $groupId)
            ->with(['customer'])
            ->orderBy('locker_number')
            ->get();

        // Create a grid structure based on group dimensions
        $grid = [];
        for ($row = 1; $row <= $group->row_count; $row++) {
            $grid[$row] = [];
            for ($col = 1; $col <= $group->column_count; $col++) {
                $grid[$row][$col] = null;
            }
        }

        // Fill grid with actual lockers based on locker_row_column
        foreach ($lockers as $locker) {
            if ($locker->locker_row_column) {
                // Parse locker_row_column like "R1C1" to get row and column
                if (preg_match('/R(\d+)C(\d+)/i', $locker->locker_row_column, $matches)) {
                    $row = (int)$matches[1];
                    $col = (int)$matches[2];

                    // Check if row and column are within bounds
                    if (
                        $row >= 1 && $row <= $group->row_count &&
                        $col >= 1 && $col <= $group->column_count
                    ) {
                        $grid[$row][$col] = $locker;
                    }
                }
            }
        }

        return response()->json([
            'group' => $group,
            'grid' => $grid,
            'lockers' => $lockers
        ]);
    }

    /**
     * Get available lockers for a specific group.
     */
    public function getAvailableLockersByGroup(Request $request, $groupId)
    {
        $group = LockerGroup::findOrFail($groupId);

        $lockers = Locker::where('locker_group_id', $groupId)
            ->where('status', 'Available')
            ->with(['customer'])
            ->orderBy('locker_number')
            ->get();

        // Create a grid structure based on group dimensions
        $grid = [];
        for ($row = 1; $row <= $group->row_count; $row++) {
            $grid[$row] = [];
            for ($col = 1; $col <= $group->column_count; $col++) {
                $grid[$row][$col] = null;
            }
        }

        // Fill grid with actual lockers based on locker_row_column
        foreach ($lockers as $locker) {
            if ($locker->locker_row_column) {
                // Parse locker_row_column like "R1C1" to get row and column
                if (preg_match('/R(\d+)C(\d+)/i', $locker->locker_row_column, $matches)) {
                    $row = (int)$matches[1];
                    $col = (int)$matches[2];

                    // Check if row and column are within bounds
                    if (
                        $row >= 1 && $row <= $group->row_count &&
                        $col >= 1 && $col <= $group->column_count
                    ) {
                        $grid[$row][$col] = $locker;
                    }
                }
            }
        }

        return response()->json([
            'group' => $group,
            'grid' => $grid,
            'lockers' => $lockers
        ]);
    }

    /**
     * Extract row and column from locker number.
     */
    private function extractPosition($lockerNumber)
    {
        // Try to extract position from locker number like "MSB001" -> row 1, col 1
        if (preg_match('/MSB(\d+)/', $lockerNumber, $matches)) {
            $number = (int)$matches[1];
            $total = $number - 1; // 0-based index

            // You may need to adjust this logic based on your actual locker numbering
            // For now, let's assume sequential numbering
            return ['row' => 1, 'col' => $number];
        }

        return null;
    }

    /**
     * API endpoint for search/filter.
     */
    public function apiSearch(Request $request)
    {
        $query = Locker::with(['customer']);

        if ($request->filled('search')) {
            $search = $request->search;
            $query->where('locker_number', 'like', "%{$search}%")
                ->orWhere('locker_type', 'like', "%{$search}%");
        }

        if ($request->filled('status')) {
            $query->where('status', $request->status);
        }

        if ($request->filled('size')) {
            $query->where('locker_size', $request->size);
        }

        if ($request->filled('type')) {
            $query->where('locker_type', $request->type);
        }

        $lockers = $query->orderBy('locker_number')->paginate(12);

        // Add URLs to each locker
        $lockers->getCollection()->transform(function ($locker) {
            $locker->url = route('lockers.show', $locker);
            $locker->edit_url = route('lockers.edit', $locker);
            return $locker;
        });

        return response()->json($lockers);
    }

    public function expiryDetails(Request $request)
    {
        $today = Carbon::today();
        $next30 = $today->copy()->addDays(30);
        $next7 = $today->copy()->addDays(7);
        $next1 = $today->copy()->addDays(1);

        $expiredCount = LockerRegistrationItem::whereDate('end_date', '<', $today)->count();

        $query = LockerRegistrationItem::with(['locker', 'registration.client'])
            ->whereNotNull('end_date')
            ->whereDate('end_date', '>=', $today)
            ->where('status', 'Active');

        if ($request->filled('search')) {
            $search = $request->search;
            $query->where(function ($q) use ($search) {
                $q->where('locker_number', 'like', "%{$search}%")
                    ->orWhere('type', 'like', "%{$search}%")
                    ->orWhereHas('locker', function ($lockerQuery) use ($search) {
                        $lockerQuery->where('locker_number', 'like', "%{$search}%")
                            ->orWhere('locker_type', 'like', "%{$search}%");
                    })
                    ->orWhereHas('registration.client', function ($clientQuery) use ($search) {
                        $clientQuery->where('name', 'like', "%{$search}%")
                            ->orWhere('phone', 'like', "%{$search}%");
                    });
            });
        }

        $summary = [
            'total_records' => (clone $query)->count(),
            'next_30_days' => (clone $query)
                ->whereDate('end_date', '<=', $next30)
                ->count(),
            'next_7_days' => (clone $query)
                ->whereDate('end_date', '<=', $next7)
                ->count(),
            'next_1_day' => (clone $query)
                ->whereDate('end_date', '<=', $next1)
                ->count(),
            'expired' => $expiredCount,
        ];

        $perPage = (int) $request->input('per_page', 10);
        if (!in_array($perPage, [10, 50, 100, 500], true)) {
            $perPage = 10;
        }

        $records = $query->orderBy('end_date')->paginate($perPage)->withQueryString();

        $search = $request->search;

        return view('lockers.expiry', compact('records', 'summary', 'search', 'perPage'));
    }
}
