<?php

namespace App\Controllers;

use App\Models\BookingModel;
use App\Models\HousekeepingTaskModel;
use App\Models\MaintenanceWorkOrderModel;
use App\Models\RoomModel;
use App\Models\RoomTypeModel;
use Config\Lookups;

class RoomController extends BaseController
{
    /**
     * Redesigned to match a user-supplied "All Rooms" mockup — stat row,
     * floor/type/status filters, live occupancy, and real "Last Cleaned"
     * data (most recent completed housekeeping task per room — see
     * HousekeepingTaskModel::lastCompletedForRoom(), null shows "Never"
     * rather than a fabricated date). Stat cards match the mockup's own
     * three (Clean/Dirty/Occupied) — Out of Service isn't hidden, it
     * still shows in the table's Status column same as any other room,
     * just not statted at the top since this tenant has none right now.
     */
    public function index()
    {
        $rooms = new RoomModel();

        $floor      = $this->request->getGet('floor');
        $roomTypeId = $this->request->getGet('room_type_id');
        $status     = $this->request->getGet('status');
        $perPage    = (int) ($this->request->getGet('perPage') ?: 10);
        $perPage    = in_array($perPage, [10, 25, 50], true) ? $perPage : 10;

        $builder = $rooms->withType();

        if ($floor !== null && $floor !== '') {
            $builder->where('rooms.floor', $floor);
        }

        if ($roomTypeId) {
            $builder->where('rooms.room_type_id', (int) $roomTypeId);
        }

        if ($status) {
            $builder->where('rooms.status', $status);
        }

        $filteredRooms = $builder->orderBy('rooms.room_number')->paginate($perPage);
        $pager         = $rooms->pager;

        $bookings    = new BookingModel();
        $housekeeping = new HousekeepingTaskModel();

        foreach ($filteredRooms as $room) {
            $room->current_guest_name = null;
            $room->current_guest_id   = null;

            if ($room->status === 'occupied') {
                $current = $bookings->withDetails()
                    ->where('bookings.room_id', $room->id)
                    ->where('bookings.status', 'checked_in')
                    ->first();

                $room->current_guest_name = $current->guest_name ?? null;
                $room->current_guest_id   = $current->guest_id ?? null;
            }

            $room->last_cleaned = $housekeeping->lastCompletedForRoom($room->id);
        }

        $totalRooms   = (new RoomModel())->countAllResults();
        $statusCounts = [];

        foreach (array_keys((new Lookups())->roomStatuses) as $key) {
            $statusCounts[$key] = (new RoomModel())->where('status', $key)->countAllResults();
        }

        $floors = array_values(array_unique(array_column((new RoomModel())->select('floor')->findAll(), 'floor')));
        sort($floors);

        return view('rooms/index', [
            'pageTitle'    => 'Rooms',
            'pageIcon'     => 'bi-door-closed',
            'pageSubtitle' => 'Manage all hotel rooms and their status.',
            'rooms'        => $filteredRooms,
            'pager'        => $pager,
            'perPage'      => $perPage,
            'totalRooms'   => $totalRooms,
            'statusCounts' => $statusCounts,
            'floors'       => $floors,
            'roomTypes'    => (new RoomTypeModel())->orderBy('name')->findAll(),
            'filters'      => ['floor' => $floor, 'room_type_id' => $roomTypeId, 'status' => $status],
            'lookups'      => new Lookups(),
        ]);
    }

    /**
     * Same filtered set index() shows, written out as CSV — no new
     * computation, just fputcsv over the same query so it can never
     * disagree with what's on screen.
     */
    public function exportCsv()
    {
        $rooms = new RoomModel();
        $builder = $rooms->withType();

        if ($floor = $this->request->getGet('floor')) {
            $builder->where('rooms.floor', $floor);
        }

        if ($roomTypeId = $this->request->getGet('room_type_id')) {
            $builder->where('rooms.room_type_id', (int) $roomTypeId);
        }

        if ($status = $this->request->getGet('status')) {
            $builder->where('rooms.status', $status);
        }

        $list = $builder->orderBy('rooms.room_number')->findAll();
        $lookups = new Lookups();

        $csv = fopen('php://temp', 'w+');
        fputcsv($csv, ['Room #', 'Type', 'Floor', 'Status']);

        foreach ($list as $room) {
            fputcsv($csv, [
                $room->room_number,
                $room->room_type_name,
                $room->floor,
                $lookups->roomStatuses[$room->status]['label'] ?? $room->status,
            ]);
        }

        rewind($csv);
        $contents = stream_get_contents($csv);
        fclose($csv);

        $this->logActivity('rooms', 'Exported rooms list CSV.');

        return $this->response
            ->setHeader('Content-Type', 'text/csv')
            ->setHeader('Content-Disposition', 'attachment; filename="rooms-' . date('Y-m-d') . '.csv"')
            ->setBody($contents);
    }

    /**
     * Redesigned to match a user-supplied "Room Management" mockup. Its
     * Room Summary legend included a "Maintenance" status — not a real
     * room status here (Config\Lookups::$roomStatuses is clean/dirty/
     * occupied/out_of_service; "Maintenance" would need the not-yet-built
     * Maintenance module, already a disabled "Soon" nav item elsewhere) —
     * so the stat cards/donut below use the 4 real statuses only, never a
     * fabricated 5th bucket. "View Room Report" was omitted for the same
     * reason "Reports & Analytics" is a disabled nav item: no reporting
     * module exists yet to link it to.
     */
    public function board()
    {
        $rooms = new RoomModel();
        $roomTypes = new RoomTypeModel();

        $floor       = $this->request->getGet('floor');
        $roomTypeId  = $this->request->getGet('room_type_id');
        $status      = $this->request->getGet('status');
        $view        = $this->request->getGet('view') === 'list' ? 'list' : 'grid';

        $builder = $rooms->withType();

        if ($floor !== null && $floor !== '') {
            $builder->where('rooms.floor', $floor);
        }

        if ($roomTypeId) {
            $builder->where('rooms.room_type_id', (int) $roomTypeId);
        }

        if ($status) {
            $builder->where('rooms.status', $status);
        }

        $filteredRooms = $builder->orderBy('rooms.floor')->orderBy('rooms.room_number')->findAll();

        // Guest name on an occupied room card — real data the mockup
        // showed (e.g. "101 Occupied — John Smith") that the first pass
        // of this redesign had available (the checked_in booking for
        // that room) but never surfaced.
        $bookings = new BookingModel();

        foreach ($filteredRooms as $room) {
            $room->current_guest_name = null;

            if ($room->status === 'occupied') {
                $current = $bookings->withDetails()
                    ->where('bookings.room_id', $room->id)
                    ->where('bookings.status', 'checked_in')
                    ->first();

                $room->current_guest_name = $current->guest_name ?? null;
            }
        }

        $totalRooms = $rooms->countAllResults();
        $statusCounts = [];
        foreach (array_keys((new Lookups())->roomStatuses) as $key) {
            $statusCounts[$key] = (new RoomModel())->where('status', $key)->countAllResults();
        }

        $floors = array_values(array_unique(array_column((new RoomModel())->select('floor')->findAll(), 'floor')));
        sort($floors);

        return view('rooms/board', [
            'pageTitle'    => 'Room Management',
            'pageSubtitle' => 'Live status for every room in the hotel.',
            'rooms'        => $filteredRooms,
            'totalRooms'   => $totalRooms,
            'statusCounts' => $statusCounts,
            'floors'       => $floors,
            'roomTypes'    => $roomTypes->orderBy('name')->findAll(),
            'filters'      => ['floor' => $floor, 'room_type_id' => $roomTypeId, 'status' => $status],
            'view'         => $view,
            'lookups'      => new Lookups(),
        ]);
    }

    /**
     * Room Details — new page from the mockup batch. Pulls together what
     * was previously only visible piecemeal elsewhere: current occupant
     * (same lookup as the Room Management board), upcoming reservations
     * for this room (real, from BookingModel), and its housekeeping/
     * maintenance history (real, filtered by room_id on the modules
     * built earlier this session) — no fabricated "asset" data or
     * occupancy-rate chart the mockup implied but this app can't back.
     */
    public function show(int $id)
    {
        $room = (new RoomModel())->withType()->where('rooms.id', $id)->first();

        if ($room === null) {
            return redirect()->to('rooms')->with('error', 'Room not found.');
        }

        $bookings = new BookingModel();

        $currentBooking = $room->status === 'occupied'
            ? $bookings->withDetails()->where('bookings.room_id', $id)->where('bookings.status', 'checked_in')->first()
            : null;

        $upcoming = $bookings->withDetails()
            ->where('bookings.room_id', $id)
            ->whereIn('bookings.status', ['confirmed', 'pending_deposit'])
            ->where('bookings.check_in_date >=', date('Y-m-d'))
            ->orderBy('bookings.check_in_date', 'asc')
            ->limit(5)
            ->findAll();

        $housekeepingTasks = (new HousekeepingTaskModel())->withDetails()
            ->where('housekeeping_tasks.room_id', $id)
            ->orderBy('housekeeping_tasks.created_at', 'desc')
            ->limit(5)
            ->findAll();

        $workOrders = (new MaintenanceWorkOrderModel())->withDetails()
            ->where('maintenance_work_orders.room_id', $id)
            ->orderBy('maintenance_work_orders.created_at', 'desc')
            ->limit(5)
            ->findAll();

        return view('rooms/show', [
            'pageTitle'         => 'Room ' . $room->room_number,
            'room'              => $room,
            'currentBooking'    => $currentBooking,
            'upcoming'          => $upcoming,
            'housekeepingTasks' => $housekeepingTasks,
            'workOrders'        => $workOrders,
            'lookups'           => new Lookups(),
        ]);
    }

    public function updateStatus(int $id)
    {
        $model  = new RoomModel();
        $room   = $model->find($id);
        $status = $this->request->getPost('status');

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

        $validStatuses = array_keys((new Lookups())->roomStatuses);

        if (! in_array($status, $validStatuses, true)) {
            return redirect()->back()->with('error', 'Invalid room status.');
        }

        $model->setStatus($id, $status);
        $this->logActivity('rooms', "Set room {$room->room_number} status to {$status}.");

        return redirect()->back()->with('success', "Room {$room->room_number} marked {$status}.");
    }

    public function new()
    {
        return view('rooms/form', [
            'pageTitle' => 'New Room',
            'room'      => null,
            'roomTypes' => (new RoomTypeModel())->orderBy('name')->findAll(),
            'lookups'   => new Lookups(),
        ]);
    }

    public function create()
    {
        $model = new RoomModel();
        $data  = $this->collectInput();

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

        $this->logActivity('rooms', 'Created room ' . $data['room_number'] . '.');

        return redirect()->to('rooms')->with('success', 'Room created.');
    }

    public function edit(int $id)
    {
        $model = new RoomModel();
        $room  = $model->find($id);

        if ($room === null) {
            return redirect()->to('rooms')->with('error', 'Room not found.');
        }

        return view('rooms/form', [
            'pageTitle' => 'Edit Room',
            'room'      => $room,
            'roomTypes' => (new RoomTypeModel())->orderBy('name')->findAll(),
            'lookups'   => new Lookups(),
        ]);
    }

    public function update(int $id)
    {
        $model = new RoomModel();

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

        $data = $this->collectInput();

        if (! $model->update($id, $data)) {
            return $this->redirectWithModelErrors($model);
        }

        $this->logActivity('rooms', 'Updated room ' . $data['room_number'] . '.');

        return redirect()->to('rooms')->with('success', 'Room updated.');
    }

    public function delete(int $id)
    {
        $model = new RoomModel();
        $room  = $model->find($id);

        if ($room === null) {
            return redirect()->to('rooms')->with('error', 'Room not found.');
        }

        $model->delete($id);
        $this->logActivity('rooms', 'Deleted room ' . $room->room_number . '.');

        return redirect()->to('rooms')->with('success', 'Room deleted.');
    }

    private function collectInput(): array
    {
        return [
            'room_number'  => $this->request->getPost('room_number'),
            'room_type_id' => (int) $this->request->getPost('room_type_id'),
            'floor'        => $this->request->getPost('floor'),
            'status'       => $this->request->getPost('status') ?: 'clean',
        ];
    }
}
