<?php

namespace App\Models;

class RoomTypeModel extends TenantModel
{
    protected $table            = 'room_types';
    protected $primaryKey       = 'id';
    protected $useAutoIncrement = true;
    protected $returnType       = 'object';
    protected $useTimestamps    = true;

    protected $allowedFields = [
        'name',
        'code',
        'description',
        'base_rate',
        'capacity',
        'amenities',
        'photo_path',
        'is_active',
    ];

    protected $validationRules = [
        'name'      => 'required|max_length[150]',
        'code'      => 'permit_empty|max_length[10]',
        'base_rate' => 'required|decimal',
        'capacity'  => 'required|integer|greater_than[0]',
    ];

    /**
     * Common hotel amenities with a matching Bootstrap Icon — offered as
     * checkboxes on the form. Deliberately not a closed enum: amenities
     * typed in before this list existed (or anything not on it) still
     * store and display fine via amenityIcon()'s fallback below, so
     * nothing in the room types already in this tenant's demo data was
     * lost or needed backfilling to fit a new schema.
     */
    public const CURATED_AMENITIES = [
        'Free Wi-Fi'         => 'bi-wifi',
        'Air conditioning'   => 'bi-snow2',
        'TV'                 => 'bi-tv',
        'Mini fridge'        => 'bi-cup-straw',
        'Work desk'          => 'bi-laptop',
        'En-suite bathroom'  => 'bi-droplet',
        'Balcony'            => 'bi-door-open',
        'Breakfast included' => 'bi-cup-hot',
        'Parking'            => 'bi-car-front',
        'In-room safe'       => 'bi-lock',
    ];

    /**
     * Icon for any amenity string, curated or not — case-insensitive
     * keyword match against the curated list above (so pre-existing free-
     * text amenities like "Free Wi-Fi"/"Wi-Fi" both land on the wifi icon)
     * falling back to a generic check icon for anything unrecognized,
     * rather than hiding it.
     */
    public static function amenityIcon(string $amenity): string
    {
        $needle = strtolower($amenity);

        foreach (self::CURATED_AMENITIES as $label => $icon) {
            $keyword = strtolower(explode(' ', $label)[0]);

            if (str_contains($needle, $keyword) || str_contains(strtolower($label), $needle)) {
                return $icon;
            }
        }

        return 'bi-check2';
    }

    /**
     * @return list<string>
     */
    public function amenitiesList(object $roomType): array
    {
        if (empty($roomType->amenities)) {
            return [];
        }

        return json_decode($roomType->amenities, true) ?: [];
    }

    /**
     * The badge code shown next to the name — real if set, otherwise
     * derived (not stored) from the name so rows created before `code`
     * existed still show something sensible instead of blank.
     */
    public function displayCode(object $roomType): string
    {
        if (! empty($roomType->code)) {
            return strtoupper($roomType->code);
        }

        return strtoupper(substr(preg_replace('/[^A-Za-z]/', '', $roomType->name), 0, 3));
    }

    public function roomCount(int $roomTypeId): int
    {
        return (new RoomModel())->where('room_type_id', $roomTypeId)->countAllResults();
    }

    /** Rooms of this type currently clean/vacant — "available now". */
    public function availableCount(int $roomTypeId): int
    {
        return (new RoomModel())->where('room_type_id', $roomTypeId)->where('status', 'clean')->countAllResults();
    }

    /**
     * Per-type occupancy right now (live room.status, not booking dates —
     * same "today uses real status" reasoning as
     * BookingModel::occupiedRoomCountOn()) for the dashboard's "Top Room
     * Types" widget. Types with zero rooms are skipped rather than shown
     * at a meaningless 0/0.
     *
     * @return list<object{name: string, total: int, occupied: int, pct: int}>
     */
    public function occupancyBreakdown(): array
    {
        $rooms = new RoomModel();
        $out   = [];

        foreach ($this->findAll() as $type) {
            $total = $rooms->where('room_type_id', $type->id)->countAllResults();

            if ($total === 0) {
                continue;
            }

            $occupied = $rooms->where('room_type_id', $type->id)->where('status', 'occupied')->countAllResults();

            $out[] = (object) [
                'name'     => $type->name,
                'total'    => $total,
                'occupied' => $occupied,
                'pct'      => (int) round($occupied / $total * 100),
            ];
        }

        usort($out, static fn ($a, $b) => $b->pct <=> $a->pct);

        return $out;
    }
}
