<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Http;
use Illuminate\Validation\ValidationException;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Mail;
use Inertia\Inertia;
use DB;
use App\Traits\DeleteModelTrait; 
use App\Models\Booking;
use App\Models\Accommodation;
use App\Models\EventRoom;
use App\Models\Room;
use App\Models\PricingRule;
use App\Mail\BookingMail;
use App\Mail\BookingConfirmationMail;
use App\Mail\BookingStatusUpdateMail;

class BookingController extends Controller
{
    use DeleteModelTrait;
    /**
     * Display a listing of the resource.
     */
    public function index()
    {
        //
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        try {
            DB::beginTransaction();

            $validatedData = $request->validate([
                'full_name'         => 'required|min:3|max:100',
                'email'             => 'nullable|email|max:100',
                'phone'             => 'nullable|string|min:10|max:15',
                'number_of_people'  => 'nullable|integer|min:1',
                'number_of_adults'  => [
                    'nullable',
                    'integer',
                    'min:1',
                    'required_if:bookable_type,accommodation', // adults only required for accommodations
                ],
                'number_of_children'=> [
                    'nullable',
                    'integer',
                    'min:0',
                ],
                'number_of_rooms'   => [
                    'nullable',
                    'integer',
                    'min:1',
                    'required_if:bookable_type,event_room',
                ],
                'special_request'   => 'nullable|string|min:10',
                'accommodation_id'  => 'nullable|exists:accommodations,id', // legacy support
                'room_id'           => 'nullable|exists:rooms,id',
                'check_in'          => 'nullable|date',
                'check_out'         => 'nullable|date|after:check_in',
                'event_start'       => 'nullable|date',
                'event_end'         => 'nullable|date|after:event_start',
                'status'            => 'nullable',
                'price'             => 'required|numeric|min:0.01',
                'price_usd'         => 'nullable|numeric|min:0',
                'price_bif'         => 'nullable|numeric|min:0',
                'confirmed_by'      => 'nullable|exists:users,id',
                'turnstile_token'   => 'required|string',
                'bookable_type'     => 'required|string|in:accommodation,event_room',
                'bookable_id'       => 'required|integer',
            ]);

            // Verify the Turnstile token with Cloudflare
            $turnstileSecretKey = config('services.turnstile.secret');
            $response = Http::asForm()->post('https://challenges.cloudflare.com/turnstile/v0/siteverify', [
                'secret' => $turnstileSecretKey,
                'response' => $validatedData['turnstile_token'],
                'remoteip' => $request->ip(),
            ]);

            $responseBody = $response->json();

            if (!$responseBody['success']) {
                // If Turnstile verification fails, throw a validation exception
                throw ValidationException::withMessages([
                    'turnstile' => 'CAPTCHA verification failed.',
                ]);
            }

            if (!$request->email && !$request->phone) {
                throw ValidationException::withMessages([
                    'contact' => 'Contact Required, Fill email or phone.',
                ]);
            }

            // For accommodation bookings, check_in and check_out are required
            $bookableClass = $validatedData['bookable_type'] === 'event_room'
                ? EventRoom::class
                : Accommodation::class;

            $selectedRoom = null; // Initialize for room assignment

            if ($bookableClass === Accommodation::class) {
                if (!$validatedData['check_in'] || !$validatedData['check_out']) {
                    throw ValidationException::withMessages([
                        'dates' => 'Check-in and check-out dates are required for accommodation bookings.',
                    ]);
                }

                $accommodation = Accommodation::find($validatedData['bookable_id']);
                if (!$accommodation) {
                    throw ValidationException::withMessages([
                        'bookable_id' => 'Selected accommodation not found.',
                    ]);
                }

                if (!empty($validatedData['room_id'])) {
                    $selectedRoom = Room::find($validatedData['room_id']);
                    
                    if (!$selectedRoom) {
                        throw ValidationException::withMessages([
                            'room_id' => 'Selected room not found.',
                        ]);
                    }
                    
                    // Verify room belongs to the selected accommodation
                    if ($selectedRoom->accommodation_id != $validatedData['bookable_id']) {
                        throw ValidationException::withMessages([
                            'room_id' => 'Selected room does not belong to the selected accommodation category.',
                        ]);
                    }

                    // Check room availability
                    if (!$selectedRoom->isAvailableForDates($validatedData['check_in'], $validatedData['check_out'])) {
                        throw ValidationException::withMessages([
                            'room_id' => "Room {$selectedRoom->room_number} is not available for the selected dates.",
                        ]);
                    }
                } else {
                    // Auto-assign first available room from the category
                    $availableRooms = $accommodation->getAvailableRooms($validatedData['check_in'], $validatedData['check_out']);
                    
                    if ($availableRooms->isEmpty()) {
                        throw ValidationException::withMessages([
                            'bookable_id' => 'No rooms available for the selected dates in this category.',
                        ]);
                    }
                    
                    // Select the first available room
                    $selectedRoom = $availableRooms->first();
                }

                // Calculate price using pricing rule if available
                if ($accommodation && $accommodation->pricingRule) {
                    $adults = $validatedData['number_of_adults'] ?? 1;
                    $children = $validatedData['number_of_children'] ?? 0;
                    
                    // Calculate price per night
                    $pricePerNight = $accommodation->pricingRule->calculatePrice($adults, $children, 'usd');
                    
                    // Calculate total price for all nights
                    $checkIn = new \DateTime($validatedData['check_in']);
                    $checkOut = new \DateTime($validatedData['check_out']);
                    $nights = $checkIn->diff($checkOut)->days;
                    $nights = max(1, $nights); // At least 1 night
                    
                    $calculatedPrice = $pricePerNight * $nights;
                    
                    if (abs($calculatedPrice - $validatedData['price']) > 0.01) {
                        \Log::info('Price discrepancy', [
                            'calculated' => $calculatedPrice,
                            'provided' => $validatedData['price'],
                        ]);
                    }
                }
            } else {
                if (!$validatedData['event_start'] || !$validatedData['event_end']) {
                    throw ValidationException::withMessages([
                        'event_dates' => 'Event start and end are required for event room bookings.',
                    ]);
                }
            }

            // Generate booking reference (MG-000000001 format for Matergo Hotel)
            $latestId = Booking::max('id') + 1;
            $bookingReference = 'MG-' . str_pad($latestId, 7, '0', STR_PAD_LEFT);

            // Create and save booking
            $booking = new Booking();
            $booking->booking_reference = $bookingReference;
            $booking->full_name = $validatedData['full_name'];
            $booking->email = $validatedData['email'];
            $booking->phone = $validatedData['phone'];
            // Guest counts: used only for accommodation pricing
            $booking->number_of_people = $validatedData['number_of_people'] ?? ($validatedData['number_of_adults'] ?? 1) + ($validatedData['number_of_children'] ?? 0);
            $booking->number_of_adults = $validatedData['number_of_adults'] ?? 1;
            $booking->number_of_children = $validatedData['number_of_children'] ?? 0;
            // Number of rooms booked: used only for event/conference room pricing (income = unit price × rooms)
            $booking->number_of_rooms = $bookableClass === EventRoom::class
                ? (int) ($validatedData['number_of_rooms'] ?? 1)
                : null;
            $booking->special_request = $validatedData['special_request'] ?? null;
            $booking->bookable_type = $bookableClass;
            $booking->bookable_id = $validatedData['bookable_id'];
            $booking->accommodation_id = $bookableClass === Accommodation::class
                ? ($validatedData['accommodation_id'] ?? $validatedData['bookable_id'])
                : null;
            // Assign room_id - either provided or auto-assigned
            $booking->room_id = $bookableClass === Accommodation::class ? ($selectedRoom->id ?? null) : null;
            $booking->check_in = $validatedData['check_in'] ?? null;
            $booking->check_out = $validatedData['check_out'] ?? null;
            $booking->event_start = $validatedData['event_start'] ?? null;
            $booking->event_end = $validatedData['event_end'] ?? null;
            $booking->price = $validatedData['price'];
            $booking->price_usd = $validatedData['price_usd'] ?? $validatedData['price'];
            $booking->price_bif = $validatedData['price_bif'] ?? null;
            $booking->status = "pending";
            $booking->confirmed_by = $validatedData['confirmed_by'] ?? null;

            $booking->save();

            // Send email notifications
            Mail::to('info@matergohotel.bi')->bcc('booking@matergohotel.bi')->send(new BookingMail($booking));
            if ($booking->email) {
                Mail::to($booking->email)->send(new BookingConfirmationMail($booking));
            }
            
            DB::commit();
            return redirect()->back()->with('booking_success', [
                'message' => "Your booking was placed successfully! Your booking reference number is {$booking->booking_reference}. We shall you contact you for confirmation.",
                'check'   => false
            ]);            
        } catch (ValidationException $e) {
            DB::rollBack();
            return redirect()->back()
                ->withErrors($e->errors())
                ->withInput();
        } catch (\Exception $e) {
            DB::rollBack();
            return redirect()->back()->with('error', [
                'message' => 'An error occurred: ' . $e->getMessage(),
                'check'   => false
            ]);
        }
    }


    /**
     * Display the specified resource.
     */
    public function show(string $id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit($id)
    {
        //
        $booking = Booking::with(['accommodation', 'room'])->findOrFail($id); 
        
        // Build room display name
        $roomDisplay = null;
        if ($booking->room) {
            $roomDisplay = "Room {$booking->room->room_number}";
            if ($booking->accommodation) {
                $category = $booking->accommodation->room_category ?? $booking->accommodation->room_name;
                $roomDisplay .= " – {$category}";
            }
        }
        
        return response()->json([
            'id' => $booking->id,
            'full_name' => $booking->full_name,
            'email' => $booking->email,
            'phone' => $booking->phone,
            'number_of_people' => $booking->number_of_people,
            'number_of_adults' => $booking->number_of_adults,
            'number_of_children' => $booking->number_of_children,
            'number_of_rooms' => $booking->number_of_rooms,
            'special_request' => $booking->special_request,
            'booking_reference' => $booking->booking_reference,
            'price' => $booking->price,
            'price_usd' => $booking->price_usd ?? $booking->price,
            'price_bif' => $booking->price_bif,
            'accommodation' => $booking->accommodation?->room_name,
            'room' => $roomDisplay,
            'room_number' => $booking->room?->room_number,
            'check_in' => $booking->check_in,
            'check_out' => $booking->check_out,
            'event_start' => $booking->event_start,
            'event_end' => $booking->event_end,
            'bookable_type' => $booking->bookable_type,
            'status' => $booking->status,
            'created_at' => $booking->created_at,
            'updated_at' => $booking->updated_at,
        ]);

    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request,$id)
    {
        //
        try {
            DB::beginTransaction();
            $validatedData = $request->validate([
                'status' => 'required|in:pending,confirmed',
                
            ]);

            // Retrieve the booking or fail.
            $booking =  Booking::findOrFail($id);

            if ($request->has('status') && $request->input('status') !== $booking->status) {
                $booking->status = $request->input('status');
            }

            $booking->fill($validatedData);
            if ($booking->isDirty()){
                $booking->save();
            } 

            // Send status update email to customer
            if ($booking->email) {
                Mail::to($booking->email)->send(new BookingStatusUpdateMail($booking));
            }
            
            DB::commit();

            return Redirect::back()->with('success', [
                'message' => 'Booking status updated to '.$booking->status,
                'check'   => false
            ]);
        } catch (ValidationException $e) {
            DB::rollBack();
            return redirect()->back()
                ->withErrors($e->errors()) 
                ->withInput(); 
        } catch (\Exception $e) {
            DB::rollBack();
            return redirect()->back()->with('error', [
                'message' => 'An error occurred:' . $e->getMessage(),
                'check'   => false
            ]);
        }
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy($id)
    {
        return $this->deleteModel($id, new Booking());
    }

    public function fetchBookings(){
        // Fetch all bookings with relationships
        $bookings = Booking::with(['accommodation', 'bookable', 'room'])
            ->orderBy('created_at', 'desc')
            ->get();
            
        return Inertia::render('bookings/Booking', [
            'bookings' => $bookings->map(function ($booking) {
                $bookableName = null;
                if ($booking->bookable) {
                    $bookableName = $booking->bookable->room_name 
                        ?? $booking->bookable->name 
                        ?? null;
                }
                
                // Build room display name
                $roomDisplay = null;
                if ($booking->room) {
                    $roomDisplay = "Room {$booking->room->room_number}";
                    if ($booking->accommodation) {
                        $category = $booking->accommodation->room_category ?? $booking->accommodation->room_name;
                        $roomDisplay .= " – {$category}";
                    }
                }
                
                return [
                    'id' => $booking->id,
                    'full_name' => $booking->full_name,
                    'email' => $booking->email,
                    'phone' => $booking->phone,
                    'status' => $booking->status,
                    'created_at' => $booking->created_at,
                    'booking_reference' => $booking->booking_reference,
                    'accommodation' => $booking->accommodation?->room_name,
                    'bookable' => $bookableName,
                    'bookable_type' => $booking->bookable_type,
                    'room' => $roomDisplay,
                    'room_number' => $booking->room?->room_number,
                    'number_of_adults' => $booking->number_of_adults,
                    'number_of_children' => $booking->number_of_children,
                    'number_of_people' => $booking->number_of_people,
                    'check_in' => $booking->check_in,
                    'check_out' => $booking->check_out,
                    'event_start' => $booking->event_start,
                    'event_end' => $booking->event_end,
                    'price' => $booking->price,
                    'price_usd' => $booking->price_usd ?? $booking->price,
                    'price_bif' => $booking->price_bif,
                ];
            }),
        ]);
    }

    /**
     * Fetch bookings data for calendar view
     */
    public function calendar()
    {
        // Fetch all confirmed bookings with relationships
        $bookings = Booking::with(['accommodation', 'room'])
            ->where('status', 'confirmed')
            ->whereNotNull('check_in')
            ->whereNotNull('check_out')
            ->get();

        // Also get all rooms for display
        $rooms = Room::with('accommodation')
            ->orderBy('accommodation_id')
            ->orderBy('room_number')
            ->get();

        // Format bookings for calendar
        $calendarBookings = $bookings->map(function ($booking) {
            $roomDisplay = null;
            $roomNumber = null;
            $category = null;
            
            if ($booking->room) {
                $roomNumber = $booking->room->room_number;
                if ($booking->accommodation) {
                    $category = $booking->accommodation->room_category ?? $booking->accommodation->room_name;
                    $roomDisplay = "Room {$roomNumber} – {$category}";
                } else {
                    $roomDisplay = "Room {$roomNumber}";
                }
            } else if ($booking->accommodation) {
                $category = $booking->accommodation->room_category ?? $booking->accommodation->room_name;
                $roomDisplay = $category;
            }

            return [
                'id' => $booking->id,
                'booking_reference' => $booking->booking_reference,
                'full_name' => $booking->full_name,
                'email' => $booking->email,
                'phone' => $booking->phone,
                'room_id' => $booking->room_id,
                'room_number' => $roomNumber,
                'room_display' => $roomDisplay,
                'category' => $category,
                'check_in' => $booking->check_in,
                'check_out' => $booking->check_out,
                'number_of_adults' => $booking->number_of_adults ?? 1,
                'number_of_children' => $booking->number_of_children ?? 0,
                'price' => $booking->price,
                'special_request' => $booking->special_request,
                'status' => $booking->status,
            ];
        });

        // Format rooms for calendar
        $calendarRooms = $rooms->map(function ($room) {
            return [
                'id' => $room->id,
                'room_number' => $room->room_number,
                'accommodation_id' => $room->accommodation_id,
                'category' => $room->accommodation->room_category ?? $room->accommodation->room_name ?? 'N/A',
                'display_name' => "Room {$room->room_number} – " . ($room->accommodation->room_category ?? $room->accommodation->room_name ?? 'N/A'),
            ];
        });

        return Inertia::render('bookings/Calendar', [
            'bookings' => $calendarBookings,
            'rooms' => $calendarRooms,
        ]);
    }

    /**
     * Preview booking confirmation email
     */
    public function previewBookingConfirmation()
    {
        $companyInfo = \App\Models\CompanyInformation::first();
        
        // Create a sample booking for preview
        $sampleBooking = (object) [
            'id' => 1,
            'booking_reference' => 'MG-0000001',
            'full_name' => 'Guest Name',
            'email' => 'guest@matergohotel.bi',
            'phone' => '+257 22 40 51 77',
            'check_in' => '2024-01-15',
            'check_out' => '2024-01-18',
            'number_of_people' => 2,
            'number_of_adults' => 2,
            'number_of_children' => 0,
            'price' => 150.00,
            'status' => 'pending',
            'special_request' => 'Late check-in requested',
        ];

        return view('emails.booking_confirmation', [
            'bookingData' => $sampleBooking,
            'companyInfo' => $companyInfo
        ]);
    }

    /**
     * Preview booking notification email (admin)
     */
    public function previewBookingNotification()
    {
        $companyInfo = \App\Models\CompanyInformation::first();
        
        // Create a sample booking for preview
        $sampleBooking = (object) [
            'id' => 1,
            'booking_reference' => 'MG-0000001',
            'full_name' => 'Guest Name',
            'email' => 'guest@matergohotel.bi',
            'phone' => '+257 22 40 51 77',
            'check_in' => '2024-01-15',
            'check_out' => '2024-01-18',
            'number_of_people' => 2,
            'number_of_adults' => 2,
            'number_of_children' => 0,
            'price' => 150.00,
            'status' => 'pending',
            'special_request' => 'Late check-in requested',
            'package' => (object) ['name' => 'Standard Room'],
            'accommodation' => 'Standard Room',
        ];

        return view('emails.booking', [
            'bookingData' => $sampleBooking,
            'companyInfo' => $companyInfo
        ]);
    }

    /**
     * Preview booking status update email
     */
    public function previewBookingStatusUpdate()
    {
        $companyInfo = \App\Models\CompanyInformation::first();
        
        // Create a sample booking for preview
        $sampleBooking = (object) [
            'id' => 1,
            'booking_reference' => 'MG-0000001',
            'full_name' => 'Guest Name',
            'email' => 'guest@matergohotel.bi',
            'phone' => '+257 22 40 51 77',
            'check_in' => '2024-01-15',
            'check_out' => '2024-01-18',
            'number_of_people' => 2,
            'number_of_adults' => 2,
            'number_of_children' => 0,
            'price' => 150.00,
            'status' => 'confirmed',
            'special_request' => null,
        ];

        return view('emails.booking_status_update', [
            'bookingData' => $sampleBooking,
            'companyInfo' => $companyInfo
        ]);
    }

}
