<?php

namespace App\Http\Controllers;

use App\Models\Booking;
use App\Models\Chef;
use App\Models\Cuisine;
use App\Models\Customer;
use App\Models\DietaryPlan;
use App\Models\MembershipPlan;
use App\Models\MenuCategory;
use App\Models\MenuItem;
use App\Models\Order;
use App\Models\Room;
use App\Models\RoomType;
use App\Models\Vendor;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Str;

class PublicController extends Controller
{
    public function home()
    {
        return view('site.home', [
            'roomTypes' => RoomType::where('status', 'active')->orderBy('base_price')->limit(4)->get(),
            'featuredDishes' => MenuItem::where('featured', true)->where('available', true)->limit(6)->get(),
            'chefs' => Chef::where('status', 'active')->where('featured', true)->limit(3)->get(),
            'plans' => MembershipPlan::where('status', 'active')->orderBy('price')->limit(3)->get(),
            'reviews' => rescue(fn () => \App\Models\Review::where('status', 'approved')->latest()->limit(6)->get(), collect(), false),
        ]);
    }

    public function rooms()
    {
        return view('site.rooms', [
            'roomTypes' => RoomType::where('status', 'active')->withCount(['rooms' => fn ($q) => $q->where('status', 'available')])->orderBy('base_price')->get(),
        ]);
    }

    public function roomType(RoomType $roomType)
    {
        return view('site.room_type', ['roomType' => $roomType->loadCount(['rooms' => fn ($q) => $q->where('status', 'available')])]);
    }

    public function dining(Request $request)
    {
        $items = MenuItem::where('available', true)
            ->when($request->filled('cuisine'), fn ($q) => $q->where('cuisine_id', $request->cuisine))
            ->when($request->filled('type'), fn ($q) => $q->where('type', $request->type))
            ->when($request->filled('diet'), fn ($q) => $q->whereJsonContains('dietary_tags', $request->diet))
            ->orderByDesc('featured')->orderBy('name')
            ->get();

        return view('site.dining', [
            'items' => $items,
            'cuisines' => Cuisine::where('status', 'active')->get(),
            'categories' => MenuCategory::orderBy('sort_order')->get(),
        ]);
    }

    public function chefs()
    {
        return view('site.chefs', ['chefs' => Chef::where('status', 'active')->orderByDesc('featured')->orderByDesc('rating')->get()]);
    }

    public function dietaryPlans()
    {
        return view('site.dietary_plans', ['plans' => DietaryPlan::where('status', 'active')->orderBy('price')->get()]);
    }

    public function bookForm(Request $request)
    {
        return view('site.book', [
            'roomTypes' => RoomType::where('status', 'active')->orderBy('base_price')->get(),
            'selected' => $request->input('room_type'),
        ]);
    }

    public function bookSubmit(Request $request)
    {
        $data = $request->validate([
            'name' => 'required|string|max:120',
            'email' => 'required|email|max:120',
            'phone' => 'required|string|max:40',
            'room_type_id' => 'required|exists:room_types,id',
            'check_in' => 'required|date|after_or_equal:today',
            'check_out' => 'required|date|after:check_in',
            'adults' => 'required|integer|min:1|max:10',
            'children' => 'nullable|integer|min:0|max:10',
            'notes' => 'nullable|string|max:1000',
            'promo_code' => 'nullable|string|max:30',
        ]);

        $roomType = RoomType::findOrFail($data['room_type_id']);

        // Find a free room of this type for the dates, if any
        $room = Room::where('room_type_id', $roomType->id)
            ->where('status', '!=', 'maintenance')
            ->whereDoesntHave('bookings', function ($q) use ($data) {
                $q->whereIn('status', ['pending', 'confirmed', 'checked_in'])
                    ->where('check_in', '<', $data['check_out'])
                    ->where('check_out', '>', $data['check_in']);
            })->orderBy('number')->first();

        $customer = Customer::firstOrCreate(
            ['email' => $data['email']],
            ['name' => $data['name'], 'phone' => $data['phone'], 'user_id' => auth()->id()]
        );

        $nights = max(1, Carbon::parse($data['check_in'])->diffInDays(Carbon::parse($data['check_out'])));
        $total = $nights * (float) $roomType->base_price;
        $notes = $data['notes'] ?? null;
        $promo = null;

        if (! empty($data['promo_code'])) {
            $promo = \App\Models\PromoCode::where('code', strtoupper($data['promo_code']))->first();

            if (! $promo || ! $promo->isValid() || ! in_array($promo->applies_to, ['bookings', 'both'])) {
                return back()->with('error', 'That promo code is not valid.')->withInput();
            }

            $discount = $promo->discountFor($total);
            $total = max(0, $total - $discount);
            $notes = trim(($notes ?? '') . "\nPromo {$promo->code} applied (−" . \App\Models\Setting::get('currency', '₦') . number_format($discount, 2) . ')');
        }

        $booking = Booking::create([
            'code' => 'BK-' . strtoupper(Str::random(6)),
            'customer_id' => $customer->id,
            'room_type_id' => $roomType->id,
            'room_id' => $room?->id,
            'check_in' => $data['check_in'],
            'check_out' => $data['check_out'],
            'adults' => $data['adults'],
            'children' => $data['children'] ?? 0,
            'status' => 'pending',
            'source' => 'website',
            'total_amount' => $total,
            'notes' => $notes,
        ]);

        $promo?->increment('used_count');

        rescue(fn () => \Illuminate\Support\Facades\Mail::to($customer->email)
            ->send(new \App\Mail\BookingReceived($booking->load(['customer', 'roomType']))), report: false);

        return view('site.book_confirmed', compact('booking', 'roomType'));
    }

    public function orderForm()
    {
        return view('site.order', [
            'items' => MenuItem::where('available', true)->orderByDesc('featured')->orderBy('name')->get(),
            'categories' => MenuCategory::orderBy('sort_order')->get(),
        ]);
    }

    public function orderSubmit(Request $request)
    {
        $data = $request->validate([
            'name' => 'required|string|max:120',
            'phone' => 'required|string|max:40',
            'type' => 'required|in:takeaway,delivery,dine_in',
            'address' => 'required_if:type,delivery|nullable|string|max:255',
            'location' => 'nullable|string|max:60',
            'items' => 'required|json',
        ]);

        $cart = collect(json_decode($data['items'], true));
        $menuItems = MenuItem::whereIn('id', $cart->pluck('id'))->where('available', true)->get()->keyBy('id');

        $lines = [];
        $subtotal = 0;

        foreach ($cart as $line) {
            $item = $menuItems->get($line['id'] ?? 0);
            $qty = max(1, (int) ($line['qty'] ?? 1));

            if (! $item) {
                continue;
            }

            $subtotal += $qty * (float) $item->price;
            $lines[] = [
                'menu_item_id' => $item->id, 'name' => $item->name, 'qty' => $qty,
                'price' => $item->price, 'total' => $qty * (float) $item->price, 'station' => $item->station,
            ];
        }

        if (! $lines) {
            return back()->with('error', 'Your basket is empty.')->withInput();
        }

        $customer = auth()->check()
            ? Customer::firstOrCreate(['user_id' => auth()->id()], ['name' => auth()->user()->name, 'email' => auth()->user()->email, 'phone' => $data['phone']])
            : null;

        $order = Order::create([
            'code' => 'ORD-' . strtoupper(Str::random(6)),
            'customer_id' => $customer?->id,
            'customer_name' => $data['name'],
            'type' => in_array($data['type'], ['delivery', 'dine_in'], true) ? $data['type'] : 'takeaway',
            'location' => $data['type'] === 'dine_in' ? ($data['location'] ?? null) : ($data['address'] ?? null),
            'status' => 'pending',
            'subtotal' => $subtotal,
            'total' => $subtotal,
            'notes' => 'Online order — ' . $data['phone'],
            'placed_at' => now(),
        ]);

        $order->items()->createMany($lines);

        return view('site.order_confirmed', compact('order'));
    }

    public function membership()
    {
        return view('site.membership', ['plans' => MembershipPlan::where('status', 'active')->orderBy('price')->get()]);
    }

    public function partners()
    {
        return view('site.partners', ['vendors' => Vendor::where('status', 'approved')->orderByDesc('rating')->get()]);
    }

    public function partnerApply(Request $request)
    {
        $data = $request->validate([
            'name' => 'required|string|max:120',
            'type' => 'required|in:hotel,restaurant,spa,travel',
            'email' => 'required|email|max:120',
            'phone' => 'required|string|max:40',
            'city' => 'required|string|max:80',
            'country' => 'required|string|max:80',
            'rooms_count' => 'nullable|integer|min:0',
            'description' => 'nullable|string|max:2000',
        ]);

        $data['slug'] = Str::slug($data['name']) . '-' . Str::lower(Str::random(4));
        $data['status'] = 'pending';

        Vendor::create($data);

        return back()->with('success', 'Application received! Our partnerships team will review it and reach out shortly.');
    }

    public function contact()
    {
        return view('site.contact');
    }
}
