<?php

namespace App\Http\Controllers;

use App\Models\Equipment;
use App\Models\EquipmentReservation;
use App\Http\Requests\EquipmentReservationRequest;
use App\Http\Requests\EquipmentReservationSlotRequest;
use Illuminate\Http\Request;
use Carbon\Carbon;
use App\Models\TimeSlot;

class EquipmentReservationController extends Controller
{
    /**
     * Display a listing of the reservations.
     */
    public function index(Request $request)
    {
        $query = EquipmentReservation::with(['equipment', 'user'])->ordered();

        // Filter by equipment
        if ($request->has('equipment_id') && $request->equipment_id != '') {
            $query->forEquipment($request->equipment_id);
        }

        // Filter by equipment type
        if ($request->has('equipment_type') && in_array($request->equipment_type, array_keys(Equipment::getTypes()))) {
            $query->whereHas('equipment', function ($q) use ($request) {
                $q->ofType($request->equipment_type);
            });
        }

        // Filter by status
        if ($request->has('status') && in_array($request->status, array_keys(EquipmentReservation::getStatuses()))) {
            $query->where('status', $request->status);
        }

        // Filter by date range
        if ($request->has('date_from') && $request->date_from != '') {
            $query->where('reservation_date', '>=', $request->date_from);
        }

        if ($request->has('date_to') && $request->date_to != '') {
            $query->where('reservation_date', '<=', $request->date_to);
        }

        // Filter by user
        if ($request->has('user_id') && $request->user_id != '') {
            $query->forUser($request->user_id);
        }

        // Search by user name or equipment name
        if ($request->has('search') && $request->search != '') {
            $search = $request->search;
            $query->where(function ($q) use ($search) {
                $q->whereHas('user', function ($userQuery) use ($search) {
                    $userQuery->where('name', 'like', "%{$search}%");
                })->orWhereHas('equipment', function ($equipmentQuery) use ($search) {
                    $equipmentQuery->where('name', 'like', "%{$search}%");
                });
            });
        }

        // AJAX support for calendar
        if ($request->has('ajax')) {
            $reservations = $query->get()->map(function ($reservation) {
                return [
                    'id' => $reservation->id,
                    'equipment_id' => $reservation->equipment_id,
                    'equipment_name' => $reservation->equipment->name ?? '',                    
                    'reservation_date' => $reservation->reservation_date,
                    'formatted_date' => \Carbon\Carbon::parse($reservation->reservation_date)->format('M d, Y'),
                    'start_time' => $reservation->start_time,
                    'end_time' => $reservation->end_time,
                    'formatted_time_range' => $reservation->start_time . ' - ' . $reservation->end_time,
                    'status' => $reservation->status,
                    'status_name' => ucfirst($reservation->status),
                    'notes' => $reservation->notes,
                ];
            });
            
            return response()->json(['reservations' => $reservations]);
        }

        $reservations = $query->paginate(15);
        $equipment = Equipment::active()->ordered()->get();
        $statuses = EquipmentReservation::getStatuses();

        return view('equipment_reservations.index', compact('reservations', 'equipment', 'statuses'));
    }

    /**
     * Show the form for creating a new reservation.
     */
    public function create(Request $request)
    {
        $equipment = Equipment::active()->ordered()->get();
        $statuses = EquipmentReservation::getStatuses();
        $selectedEquipment = null;
        $selectedDate = $request->get('date', now()->format('Y-m-d'));

        if ($request->has('equipment_id')) {
            $selectedEquipment = Equipment::find($request->equipment_id);
        }

        return view('equipment_reservations.create', compact('equipment', 'statuses', 'selectedEquipment', 'selectedDate'));
    }

    /**
     * Store a newly created reservation in storage.
     */
    public function store(EquipmentReservationSlotRequest $request)
    {
        $data = $request->validated();
        $data['user_id'] = auth()->user()->id;
        $data['status'] = 'confirmed';

        $timeSlotIds = $data['time_slot_ids'];
        $createdReservations = [];
        $timeSlotService = app(\App\Services\TimeSlotService::class);

        // Create a reservation for each selected time slot
        foreach ($timeSlotIds as $timeSlotId) {
            // Get the time slot to extract date and time information
            $timeSlot = TimeSlot::find($timeSlotId);
            
            // Create reservation data for this slot
            $reservationData = [
                'equipment_id' => $data['equipment_id'],
                'user_id' => $data['user_id'],
                'time_slot_id' => $timeSlotId,
                'reservation_date' => $timeSlot->slot_date,
                'start_time' => $timeSlot->start_time->format('H:i'),
                'end_time' => $timeSlot->end_time->format('H:i'),
                'status' => $data['status'],
                'notes' => $data['notes'] ?? null,
            ];

            // Create the reservation
            $reservation = EquipmentReservation::create($reservationData);
            $createdReservations[] = $reservation;

            // Update the time slot status and link it to the reservation
            $timeSlotService->reserveTimeSlot($reservation);
        }

        $slotCount = count($createdReservations);
        $message = $slotCount === 1 
            ? 'Reservation created successfully.' 
            : "{$slotCount} reservations created successfully.";

        return redirect()->route('equipment-reservations.index')
            ->with('success', $message);
    }

    /**
     * Display the specified reservation.
     */
    public function show(EquipmentReservation $equipmentReservation)
    {
        $equipmentReservation->load(['equipment', 'user']);
        return view('equipment_reservations.show', compact('equipmentReservation'));
    }

    /**
     * Show the form for editing the specified reservation.
     */
    public function edit(EquipmentReservation $equipmentReservation)
    {
        $equipment = Equipment::active()->ordered()->get();
        $statuses = EquipmentReservation::getStatuses();
        return view('equipment_reservations.edit', compact('equipmentReservation', 'equipment', 'statuses'));
    }

    /**
     * Update the specified reservation in storage.
     */
    public function update(EquipmentReservationRequest $request, EquipmentReservation $equipmentReservation)
    {
        $data = $request->validated();

        // Additional check to prevent updating to past time slots
        $slotDateTime = Carbon::parse($data['reservation_date'])->setTimeFrom(Carbon::parse($data['start_time']));
        if ($slotDateTime->isPast()) {
            return redirect()->back()
                ->withErrors(['time_slot' => 'Cannot update a reservation to a time slot in the past.'])
                ->withInput();
        }

        // Store old values for time slot management
        $oldEquipmentId = $equipmentReservation->equipment_id;
        $oldDate = $equipmentReservation->reservation_date;
        $oldStartTime = $equipmentReservation->start_time;

        // Calculate end time based on slot duration
        $equipment = Equipment::find($data['equipment_id']);
        $startTime = Carbon::parse($data['start_time']);
        $endTime = $startTime->copy()->addMinutes($equipment->slot_duration);
        $data['end_time'] = $endTime->format('H:i');

        // Update the reservation
        $equipmentReservation->update($data);

        // Handle time slot changes
        $timeSlotService = app(\App\Services\TimeSlotService::class);
        
        // If equipment, date, or time changed, release old slot and reserve new slot
        if ($oldEquipmentId != $data['equipment_id'] || 
            $oldDate != $data['reservation_date'] || 
            $oldStartTime != $data['start_time']) {
            
            // Release the old time slot
            $oldReservation = $equipmentReservation->replicate();
            $oldReservation->equipment_id = $oldEquipmentId;
            $oldReservation->reservation_date = $oldDate;
            $oldReservation->start_time = $oldStartTime;
            $timeSlotService->releaseTimeSlot($oldReservation);
            
            // Reserve the new time slot
            $timeSlotService->reserveTimeSlot($equipmentReservation);
        }

        return redirect()->route('equipment-reservations.index')
            ->with('success', 'Reservation updated successfully.');
    }

    /**
     * Remove the specified reservation from storage.
     */
    public function destroy(EquipmentReservation $equipmentReservation)
    {
        // Check if reservation is in the past
        if ($equipmentReservation->isPast()) {
            return redirect()->back()
                ->with('error', 'Cannot delete past reservations.');
        }

        // Release the time slot to make it available again
        $timeSlotService = app(\App\Services\TimeSlotService::class);
        $timeSlotService->releaseTimeSlot($equipmentReservation);

        $equipmentReservation->delete();

        return redirect()->route('equipment-reservations.index')
            ->with('success', 'Reservation deleted successfully.');
    }

    /**
     * Cancel a reservation.
     */
    public function cancel(EquipmentReservation $equipmentReservation)
    {
        // Check if user is authorized to cancel this reservation
        // Users can only cancel their own reservations, admins can cancel any
        if (!auth()->user()->isAdmin() && $equipmentReservation->user_id !== auth()->id()) {
            return redirect()->back()
                ->with('error', 'You are not authorized to cancel this reservation.');
        }
        
        if ($equipmentReservation->isCancelled()) {
            return redirect()->back()
                ->with('error', 'Reservation is already cancelled.');
        }

        if ($equipmentReservation->isPast()) {
            return redirect()->back()
                ->with('error', 'Cannot cancel past reservations.');
        }

        $equipmentReservation->update(['status' => 'cancelled']);

        // Release the time slot to make it available again
        $timeSlotService = app(\App\Services\TimeSlotService::class);
        $timeSlotService->releaseTimeSlot($equipmentReservation);

        return redirect()->back()
            ->with('success', 'Reservation cancelled successfully.');
    }

    /**
     * Complete a reservation.
     */
    public function complete(EquipmentReservation $equipmentReservation)
    {
        // Check if user is authorized to complete this reservation
        // Users can only complete their own reservations, admins can complete any
        if (!auth()->user()->isAdmin() && $equipmentReservation->user_id !== auth()->id()) {
            return redirect()->back()
                ->with('error', 'You are not authorized to complete this reservation.');
        }

        if ($equipmentReservation->isCompleted()) {
            return redirect()->back()
                ->with('error', 'Reservation is already completed.');
        }

        if ($equipmentReservation->isFuture()) {
            return redirect()->back()
                ->with('error', 'Cannot complete future reservations.');
        }

        $equipmentReservation->update(['status' => 'completed']);

        return redirect()->back()
            ->with('success', 'Reservation marked as completed.');
    }

    /**
     * Show user's own reservations.
     */
    public function myReservations(Request $request)
    {
        $query = EquipmentReservation::with('equipment')
            ->forUser(auth()->id())
            ->ordered();

        // Filter by status
        if ($request->has('status') && in_array($request->status, array_keys(EquipmentReservation::getStatuses()))) {
            $query->where('status', $request->status);
        }

        // Filter by date range
        if ($request->has('date_from')) {
            $query->where('reservation_date', '>=', $request->date_from);
        }

        if ($request->has('date_to')) {
            $query->where('reservation_date', '<=', $request->date_to);
        }

        $reservations = $query->paginate(15);
        $statuses = EquipmentReservation::getStatuses();

        return view('equipment_reservations.my_reservations', compact('reservations', 'statuses'));
    }

    /**
     * Show calendar view for equipment reservations.
     */
    public function calendar(Request $request)
    {
        $equipment = Equipment::active()->ordered()->get();
        $selectedEquipment = null;
        $selectedDate = $request->get('date', now()->format('Y-m-d'));

        if ($request->has('equipment_id')) {
            $selectedEquipment = Equipment::find($request->equipment_id);
        }

        return view('equipment_reservations.calendar', compact('equipment', 'selectedEquipment', 'selectedDate'));
    }

    /**
     * Get time slots for equipment on a specific date.
     */
    public function getTimeSlots(Request $request)
    {
        $request->validate([
            'equipment_id' => 'required|exists:equipment,id',
            'date' => 'required|date|after_or_equal:today',
        ]);

        $equipment = Equipment::find($request->equipment_id);
        $date = $request->date;

        $timeSlots = $equipment->getTimeSlotsForDate($date);

        return response()->json([
            'success' => true,
            'data' => [
                'equipment' => $equipment->toApiArray(),
                'date' => $date,
                'available_slots' => $timeSlots,
                'total_available' => $equipment->getAvailableSlotsForDate($date),
            ],
            'message' => 'Available time slots retrieved successfully'
        ]);
    }

    /**
     * Get reservation statistics.
     */
    public function statistics()
    {
        $stats = [
            'total' => EquipmentReservation::count(),
            'confirmed' => EquipmentReservation::confirmed()->count(),
            'cancelled' => EquipmentReservation::where('status', 'cancelled')->count(),
            'completed' => EquipmentReservation::where('status', 'completed')->count(),
            'today' => EquipmentReservation::forDate(now()->toDateString())->count(),
            'upcoming' => EquipmentReservation::where('reservation_date', '>', now()->toDateString())->count(),
            'past' => EquipmentReservation::where('reservation_date', '<', now()->toDateString())->count(),
            'by_equipment' => [],
            'by_status' => [],
        ];

        // Get statistics by equipment
        $equipmentStats = EquipmentReservation::with('equipment')
            ->selectRaw('equipment_id, COUNT(*) as total, status, COUNT(*) as count')
            ->groupBy('equipment_id', 'status')
            ->get();

        foreach ($equipmentStats as $stat) {
            if (!isset($stats['by_equipment'][$stat->equipment_id])) {
                $stats['by_equipment'][$stat->equipment_id] = [
                    'name' => $stat->equipment->name,
                    'total' => 0,
                    'confirmed' => 0,
                    'cancelled' => 0,
                    'completed' => 0,
                ];
            }
            $stats['by_equipment'][$stat->equipment_id]['total'] += $stat->total;
            $stats['by_equipment'][$stat->equipment_id][$stat->status] = $stat->count;
        }

        // Get statistics by status
        foreach (EquipmentReservation::getStatuses() as $status => $name) {
            $stats['by_status'][$status] = [
                'name' => $name,
                'count' => EquipmentReservation::where('status', $status)->count(),
            ];
        }

        return view('equipment_reservations.statistics', compact('stats'));
    }
}
