<?php

namespace App\Http\Controllers;

use App\Models\Service;
use App\Models\Consultant;
use App\Models\Booking;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Carbon\Carbon;

class BookingController extends Controller
{
    private const SLOT_START_TIME = '09:00';
    private const SLOT_END_TIME = '18:00';
    private const SLOT_MINUTES = 30;

    private function getAvailableSlots(int $consultantId, Carbon $date, ?int $ignoreBookingId = null): array
    {
        $dayStart = Carbon::parse($date->format('Y-m-d') . ' ' . self::SLOT_START_TIME);
        $dayEnd = Carbon::parse($date->format('Y-m-d') . ' ' . self::SLOT_END_TIME);

        $slots = [];
        $cursor = $dayStart->copy();
        while ($cursor->lt($dayEnd)) {
            $slots[] = $cursor->format('H:i');
            $cursor->addMinutes(self::SLOT_MINUTES);
        }

        // Remove past slots if booking for today
        if ($date->isToday()) {
            $now = now();
            $slots = array_values(array_filter($slots, function (string $time) use ($date, $now) {
                $dt = Carbon::createFromFormat('Y-m-d H:i', $date->format('Y-m-d') . ' ' . $time);
                return $dt->gt($now);
            }));
        }

        $bookedQuery = Booking::where('consultant_id', $consultantId)
            ->whereIn('status', ['pending', 'confirmed'])
            ->whereDate('scheduled_at', $date->toDateString());

        if ($ignoreBookingId) {
            $bookedQuery->where('id', '!=', $ignoreBookingId);
        }

        $bookedTimes = $bookedQuery
            ->pluck('scheduled_at')
            ->map(fn ($dt) => Carbon::parse($dt)->format('H:i'))
            ->unique()
            ->values()
            ->all();

        return array_values(array_diff($slots, $bookedTimes));
    }

    // 1. Show the Booking Form
    public function create(Request $request)
    {
        // If the URL has ?service_slug=..., pre-select that service
        $selectedService = null;
        if ($request->has('service')) {
            $selectedService = Service::where('slug', $request->get('service'))->first();
        } elseif ($request->has('service_id')) {
            $selectedService = Service::find($request->get('service_id'));
        }

        $services = Service::where('is_active', true)->get();
        // Get consultants with their User info loaded
        $consultants = Consultant::with('user')->get();

        return view('booking.create', compact('services', 'consultants', 'selectedService'));
    }

    public function availableSlots(Request $request)
    {
        $validated = $request->validate([
            'consultant_id' => 'required|exists:consultants,id',
            'date' => 'required|date|after_or_equal:today',
        ]);

        $date = Carbon::parse($validated['date']);
        $slots = $this->getAvailableSlots((int) $validated['consultant_id'], $date);

        return response()->json([
            'date' => $date->toDateString(),
            'slots' => $slots,
        ]);
    }

    // 2. Store the Booking
    public function store(Request $request)
    {
        // Validate inputs
        $validated = $request->validate([
            'service_id' => 'required|exists:services,id',
            'consultant_id' => 'required|exists:consultants,id',
            'booking_date' => 'required|date|after_or_equal:today',
            'booking_time' => 'required',
            'payment_proof' => 'required|image|max:2048', // Max 2MB image
        ]);

        // Upload Image
        $proofPath = $request->file('payment_proof')->store('payments', 'public');


        // Combine Date and Time into one timestamp
        $bookingDate = Carbon::parse($validated['booking_date']);
        $available = $this->getAvailableSlots((int) $validated['consultant_id'], $bookingDate);
        if (!in_array($validated['booking_time'], $available, true)) {
            return back()
                ->withErrors(['booking_time' => 'This time is not available for the selected consultant/date. Please choose another slot.'])
                ->withInput();
        }

        $scheduledAt = Carbon::createFromFormat('Y-m-d H:i', $validated['booking_date'] . ' ' . $validated['booking_time']);

        // Check if consultant already booked (pending or confirmed) at this exact time
        $exists = Booking::where('consultant_id', $validated['consultant_id'])
            ->whereIn('status', ['pending', 'confirmed'])
            ->where('scheduled_at', $scheduledAt)
            ->exists();

        if ($exists) {
            return back()
                ->withErrors(['booking_time' => 'This consultant is already booked at that time. Please choose another slot.'])
                ->withInput();
        }

        // Create the booking
        Booking::create([
            'user_id' => Auth::id(), // The logged-in client
            'service_id' => $validated['service_id'],
            'consultant_id' => $validated['consultant_id'],
            'scheduled_at' => $scheduledAt,
            'status' => 'pending', // Default status
            'payment_proof' => $proofPath,

        ]);


        // Redirect to Dashboard with success message
        return redirect()->route('dashboard')->with('success', 'Booking requested successfully! Waiting for confirmation.');
    }

    public function editSchedule(Booking $booking)
    {
        abort_unless($booking->user_id === Auth::id(), 403);
        abort_unless($booking->status === 'pending', 403);

        return view('booking.reschedule', compact('booking'));
    }

    public function updateSchedule(Request $request, Booking $booking)
    {
        abort_unless($booking->user_id === Auth::id(), 403);
        abort_unless($booking->status === 'pending', 403);

        $validated = $request->validate([
            'booking_date' => 'required|date|after_or_equal:today',
            'booking_time' => 'required',
        ]);

        $bookingDate = Carbon::parse($validated['booking_date']);
        $available = $this->getAvailableSlots((int) $booking->consultant_id, $bookingDate, $booking->id);
        if (!in_array($validated['booking_time'], $available, true)) {
            return back()
                ->withErrors(['booking_time' => 'This time is not available for the selected consultant/date. Please choose another slot.'])
                ->withInput();
        }

        $scheduledAt = Carbon::createFromFormat('Y-m-d H:i', $validated['booking_date'] . ' ' . $validated['booking_time']);
        if ($scheduledAt->isPast()) {
            return back()->withErrors(['booking_date' => 'Please select a future date/time.'])->withInput();
        }

        // Check conflict for this consultant, excluding current booking
        $exists = Booking::where('consultant_id', $booking->consultant_id)
            ->whereIn('status', ['pending', 'confirmed'])
            ->where('scheduled_at', $scheduledAt)
            ->where('id', '!=', $booking->id)
            ->exists();

        if ($exists) {
            return back()
                ->withErrors(['booking_time' => 'This consultant is already booked at that time. Please choose another slot.'])
                ->withInput();
        }

        $booking->update([
            'scheduled_at' => $scheduledAt,
        ]);

        return redirect()->route('dashboard')->with('success', 'Booking rescheduled successfully.');
    }

    public function cancel(Booking $booking)
    {
        abort_unless($booking->user_id === Auth::id(), 403);
        abort_unless($booking->status === 'pending', 403);

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

        return redirect()->route('dashboard')->with('success', 'Booking cancelled.');
    }
}
