<?php

namespace App\Controllers;

use App\Libraries\PhoneNumber;
use App\Models\DiningMembershipModel;
use App\Models\DiningTableModel;
use App\Models\GuestModel;
use App\Models\RestaurantReservationModel;
use Config\Lookups;

class RestaurantReservationController extends BaseController
{
    /**
     * Floor/capacity view for a given date — every table colored by
     * available/booked/occupied for that day, plus the reservation list
     * underneath. Table state is computed per-slot from reservations, not
     * stored (see CreateDiningTablesTable migration).
     */
    public function index()
    {
        $date = $this->request->getGet('date') ?: date('Y-m-d');

        $tables = (new DiningTableModel())->withArea()->orderBy('dining_areas.name')->orderBy('dining_tables.table_number')->findAll();
        $reservations = (new RestaurantReservationModel())->forDate($date);

        // Which tables have ANY booked/seated reservation today, for the
        // simple floor summary (a specific time-slot check happens when
        // actually creating a reservation, via hasConflict()).
        $bookedTableIds = array_unique(array_filter(array_map(
            static fn ($r) => $r->status === 'cancelled' || $r->status === 'no_show' ? null : $r->dining_table_id,
            $reservations
        )));

        return view('dining/reservations_index', [
            'pageTitle'      => 'Restaurant Reservations',
            'date'           => $date,
            'tables'         => $tables,
            'reservations'   => $reservations,
            'bookedTableIds' => $bookedTableIds,
            'lookups'        => new Lookups(),
        ]);
    }

    public function new()
    {
        return view('dining/reservation_form', [
            'pageTitle' => 'New Reservation',
            'tables'    => (new DiningTableModel())->withArea()->orderBy('table_number')->findAll(),
            'date'      => $this->request->getGet('date') ?: date('Y-m-d'),
        ]);
    }

    public function create()
    {
        $guestId   = (int) $this->request->getPost('guest_id');
        $walkInName = $this->request->getPost('walk_in_name');
        $walkInPhone = $this->request->getPost('walk_in_phone');

        if ($guestId <= 0 && empty($walkInName)) {
            return redirect()->back()->withInput()->with('error', 'Provide an existing guest or a walk-in name.');
        }

        $tableId = $this->request->getPost('dining_table_id') ?: null;
        $model   = new RestaurantReservationModel();

        if ($tableId && $model->hasConflict((int) $tableId, $this->request->getPost('reservation_date'), $this->request->getPost('reservation_time'))) {
            return redirect()->back()->withInput()->with('error', 'That table is already booked for this exact date and time.');
        }

        $data = [
            'guest_id'         => $guestId > 0 ? $guestId : null,
            'walk_in_name'     => $guestId > 0 ? null : $walkInName,
            'walk_in_phone'    => $guestId > 0 ? null : $walkInPhone,
            'party_size'       => (int) $this->request->getPost('party_size'),
            'reservation_date' => $this->request->getPost('reservation_date'),
            'reservation_time' => $this->request->getPost('reservation_time'),
            'dining_table_id'  => $this->request->getPost('dining_table_id') ?: null,
            'status'           => 'booked',
        ];

        if (! $model->insert($data)) {
            return $this->redirectWithModelErrors($model);
        }

        $this->logActivity('dining', 'Booked table reservation for ' . ($data['walk_in_name'] ?? "guest #{$guestId}") . " ({$data['party_size']} guests, {$data['reservation_date']} {$data['reservation_time']}).");

        return redirect()->to('dining/reservations?date=' . $data['reservation_date'])->with('success', 'Reservation booked.');
    }

    public function seat(int $id)
    {
        return $this->transition($id, 'seated', 'Marked seated');
    }

    public function complete(int $id)
    {
        $reservation = (new RestaurantReservationModel())->find($id);

        $result = $this->transition($id, 'completed', 'Marked completed');

        if ($reservation !== null && $reservation->guest_id !== null) {
            $this->sendPostDiningFeedbackRequest($reservation->guest_id);
        }

        return $result;
    }

    /**
     * Same 'post_stay_feedback' message type CheckOutController already
     * uses for room stays — no new message type needed, this is just the
     * F&B-side trigger for it (Phase 1 gap: previously only fired at room
     * checkout, never after a restaurant meal). Walk-ins with no guest_id
     * can't be messaged, so complete() only calls this when one exists.
     */
    private function sendPostDiningFeedbackRequest(int $guestId): void
    {
        $guest = (new GuestModel())->find($guestId);

        if ($guest === null) {
            return;
        }

        service('messagingService')->send(
            'post_stay_feedback',
            $guest->id,
            $guest->phone,
            "Hi {$guest->full_name}, thank you for dining with us! We'd love to hear about your experience — please reply and let us know how it was.",
            [$guest->full_name],
        );
    }

    public function cancel(int $id)
    {
        return $this->transition($id, 'cancelled', 'Cancelled');
    }

    public function noShow(int $id)
    {
        $model = new RestaurantReservationModel();
        $reservation = $model->find($id);

        if ($reservation === null) {
            return redirect()->back()->with('error', 'Reservation not found.');
        }

        $model->markNoShow($id);
        $this->logActivity('dining', "Marked reservation #{$id} a no-show.");

        return redirect()->back()->with('success', 'Marked no-show.');
    }

    private function transition(int $id, string $status, string $verb)
    {
        $model = new RestaurantReservationModel();

        if ($model->find($id) === null) {
            return redirect()->back()->with('error', 'Reservation not found.');
        }

        $model->update($id, ['status' => $status]);
        $this->logActivity('dining', "{$verb} reservation #{$id}.");

        return redirect()->back()->with('success', $verb . '.');
    }

    /**
     * Used by the new-reservation form's phone lookup (same pattern as
     * Phase 1's booking-creation flow).
     */
    public function lookupGuest()
    {
        $phone      = (string) $this->request->getGet('phone');
        $normalized = PhoneNumber::normalize($phone);

        if ($normalized === null) {
            return $this->response->setJSON(['found' => false]);
        }

        $guest = (new GuestModel())->where('phone', $normalized)->first();

        if ($guest === null) {
            return $this->response->setJSON(['found' => false]);
        }

        $lookups  = new Lookups();
        $segMeta  = $lookups->guestSegments[$guest->segment] ?? null;
        $dining   = (new DiningMembershipModel())->forGuest($guest->id);
        $dineMeta = $dining && $dining->status === 'active' ? ($lookups->diningMembershipTiers[$dining->tier] ?? null) : null;

        return $this->response->setJSON([
            'found' => true,
            'guest' => [
                'id'           => $guest->id,
                'full_name'    => $guest->full_name,
                'phone'        => $guest->phone,
                'segmentLabel' => $segMeta['label'] ?? null,
                'segmentBadge' => $segMeta['badge'] ?? null,
                'diningLabel'  => $dineMeta['label'] ?? null,
                'diningBadge'  => $dineMeta['badge'] ?? null,
            ],
        ]);
    }
}
