<?php

namespace App\Controllers;

use App\Models\BookingModel;
use App\Models\RatePlanModel;
use App\Models\RoomModel;
use App\Models\RoomTypeModel;

/**
 * Staff Booking Assistant — manager/front_desk only, read-only chat over
 * real availability/rate/booking data via tool calls (check_availability,
 * search_bookings below). Claude never invents a room number, a rate, or
 * a booking — every answer traces back to a real tool call's real
 * result, and if a tool genuinely can't answer the question, Claude is
 * instructed to say so rather than guess. No booking-modifying actions
 * here at all; booking creation stays in the existing Phase 1 wizard.
 */
class AiAssistantController extends BaseController
{
    public function index()
    {
        return view('ai_assistant/index', [
            'pageTitle' => 'Staff Booking Assistant',
        ]);
    }

    /**
     * Stateless chat turn — the client sends the full conversation so
     * far (its own prior turns + this new question) and gets back
     * Claude's reply; nothing is persisted server-side between turns
     * (every call is still logged to ai_call_log for audit, same as
     * every other AI feature).
     */
    public function ask()
    {
        if (service('settings')->get('ai.staff_assistant_enabled', '1') !== '1') {
            return $this->response->setJSON(['success' => false, 'error' => 'Staff Booking Assistant is turned off — enable it under Settings > AI Features.', 'csrf_hash' => csrf_hash()]);
        }

        $messagesJson = $this->request->getPost('messages');
        $messages     = json_decode((string) $messagesJson, true);

        if (! is_array($messages) || $messages === []) {
            return $this->response->setJSON(['success' => false, 'error' => 'No question provided.', 'csrf_hash' => csrf_hash()]);
        }

        // Only role/content survive the round-trip from the client — no
        // other field is trusted from a JSON blob the browser sent.
        $messages = array_map(static fn ($m) => ['role' => $m['role'] ?? 'user', 'content' => $m['content'] ?? ''], $messages);

        $tools = [
            [
                'name'        => 'check_availability',
                'description' => 'Checks which real rooms are free for a date range, with their real nightly rate for that check-in date (rate plans already applied). Optionally filter by room type name and/or a maximum nightly rate.',
                'input_schema' => [
                    'type'       => 'object',
                    'properties' => [
                        'check_in'      => ['type' => 'string', 'description' => 'YYYY-MM-DD'],
                        'check_out'     => ['type' => 'string', 'description' => 'YYYY-MM-DD'],
                        'room_type_name' => ['type' => 'string', 'description' => 'Optional — a room type name or partial name, e.g. "twin" or "deluxe".'],
                        'max_rate'      => ['type' => 'number', 'description' => 'Optional — maximum nightly rate in GHS.'],
                    ],
                    'required' => ['check_in', 'check_out'],
                ],
            ],
            [
                'name'        => 'search_bookings',
                'description' => 'Looks up real bookings — arrivals, departures, or currently in-house guests — for a given date.',
                'input_schema' => [
                    'type'       => 'object',
                    'properties' => [
                        'date' => ['type' => 'string', 'description' => 'YYYY-MM-DD'],
                        'type' => ['type' => 'string', 'enum' => ['arrivals', 'departures', 'in_house']],
                    ],
                    'required' => ['date', 'type'],
                ],
            ],
        ];

        $executor = function (string $name, array $input) {
            if ($name === 'check_availability') {
                return json_encode($this->checkAvailabilityTool($input));
            }

            if ($name === 'search_bookings') {
                return json_encode($this->searchBookingsTool($input));
            }

            return json_encode(['error' => 'Unknown tool.']);
        };

        $systemPrompt = "Today's date is " . date('Y-m-d') . '. You are a read-only assistant for hotel staff, '
            . 'answering questions about room availability, rates, and bookings via the check_availability and '
            . 'search_bookings tools. Never invent a room number, a rate, a guest name, or a booking detail — every '
            . 'fact in your answer must come from a tool result. If a tool result is empty or a question can\'t be '
            . 'answered with these two tools (e.g. it asks you to create/modify/cancel a booking, or asks about data '
            . 'these tools don\'t cover), say so plainly rather than guessing. You cannot create, modify, or cancel '
            . 'any booking — if asked to do so, tell the user to use the New Booking / Reservations screens.';

        $result = service('claudeService')->chat(
            'staff_assistant',
            $systemPrompt,
            $messages,
            $tools,
            $executor,
            null,
            null,
            $this->currentUserId(),
        );

        if (! $result['success']) {
            return $this->response->setJSON(['success' => false, 'error' => $result['error'], 'csrf_hash' => csrf_hash()]);
        }

        return $this->response->setJSON(['success' => true, 'text' => $result['text'], 'csrf_hash' => csrf_hash()]);
    }

    /**
     * The real query behind check_availability — RoomModel::findAvailable()
     * (the exact same overlap check the New Booking wizard's room search
     * already uses) plus RatePlanModel::resolveRate() (the exact same
     * rate resolution folios/bookings already use) for each room's real
     * nightly rate on the given check-in date. Capped at 20 rooms.
     */
    private function checkAvailabilityTool(array $input): array
    {
        $checkIn  = $input['check_in']  ?? null;
        $checkOut = $input['check_out'] ?? null;

        if (! $checkIn || ! $checkOut || ! strtotime($checkIn) || ! strtotime($checkOut)) {
            return ['error' => 'check_in and check_out must be valid YYYY-MM-DD dates.'];
        }

        $roomTypeId = null;

        if (! empty($input['room_type_name'])) {
            $match = (new RoomTypeModel())->like('name', $input['room_type_name'])->first();

            if ($match === null) {
                return ['rooms' => [], 'note' => 'No room type matches "' . $input['room_type_name'] . '" — real room types were checked by name and none matched.'];
            }

            $roomTypeId = $match->id;
        }

        $rooms = (new RoomModel())->findAvailable($checkIn, $checkOut, $roomTypeId);
        $rateModel = new RatePlanModel();

        $results = [];

        foreach (array_slice($rooms, 0, 20) as $room) {
            $rate = $rateModel->resolveRate((int) $room->room_type_id, $checkIn, $room->base_rate);

            if (! empty($input['max_rate']) && (float) $rate > (float) $input['max_rate']) {
                continue;
            }

            $results[] = [
                'room_number'  => $room->room_number,
                'room_type'    => $room->room_type_name,
                'nightly_rate' => $rate,
                'capacity'     => (int) $room->capacity,
            ];
        }

        return ['rooms' => $results, 'total_available_before_rate_filter' => count($rooms)];
    }

    private function searchBookingsTool(array $input): array
    {
        $date = $input['date'] ?? null;
        $type = $input['type'] ?? null;

        if (! $date || ! strtotime($date)) {
            return ['error' => 'date must be a valid YYYY-MM-DD date.'];
        }

        $bookings = new BookingModel();

        if ($type === 'arrivals') {
            $rows = $bookings->arrivalsOn($date);
        } elseif ($type === 'departures') {
            $rows = $bookings->departuresOn($date);
        } elseif ($type === 'in_house') {
            $rows = $bookings->withDetails()
                ->where('bookings.status', 'checked_in')
                ->where('bookings.check_in_date <=', $date)
                ->where('bookings.check_out_date >', $date)
                ->findAll();
        } else {
            return ['error' => 'type must be one of arrivals, departures, in_house.'];
        }

        return array_map(static fn ($b) => [
            'guest_name' => $b->guest_name,
            'room'       => $b->room_number,
            'room_type'  => $b->room_type_name,
            'check_in'   => $b->check_in_date,
            'check_out'  => $b->check_out_date,
        ], array_slice($rows, 0, 20));
    }
}
