# Phase 3: Rate Management

## Objective
Implement seasonal rate management, rate engine service, and availability checking for both Filament admin and API.

---

## Tasks

### 3.1 Filament — SeasonalRatesRelationManager

**File:** `app/Filament/Resources/HotelResource/RelationManagers/SeasonalRatesRelationManager.php`

CRUD for seasonal rates inline on HotelResource or HotelRoomType:
- Form: name, room_type, season (enum), start_date, end_date, prices (3-tier), min_stay, max_stay, is_active
- Table: name, room_type, season, date range, price, is_active
- Validation: date ranges must not overlap for same room type

### 3.2 HotelRateService

**File:** `app/Services/HotelManager/HotelRateService.php`

Core rate engine:

```php
final class HotelRateService
{
    /**
     * Get the applicable nightly rate for a room type on a specific date.
     * Priority: active seasonal rate > room type base price.
     */
    public function getNightlyRate(
        HotelRoomType $roomType,
        CarbonImmutable $date,
        bool $isMember = false,
        bool $isResortAccess = false,
    ): Money;

    /**
     * Calculate total stay price for date range.
     * Each night may have a different rate (seasonal boundaries).
     */
    public function calculateStayPrice(
        HotelRoomType $roomType,
        CarbonImmutable $checkIn,
        CarbonImmutable $checkOut,
        bool $isMember = false,
        bool $isResortAccess = false,
    ): Money;

    /**
     * Get nightly breakdown for a date range.
     * Returns array of [date => Money] for display purposes.
     */
    public function getNightlyBreakdown(
        HotelRoomType $roomType,
        CarbonImmutable $checkIn,
        CarbonImmutable $checkOut,
        bool $isMember = false,
    ): array;
}
```

### 3.3 HotelAvailabilityService

**File:** `app/Services/HotelManager/HotelAvailabilityService.php`

```php
final class HotelAvailabilityService
{
    /**
     * Get available room count per room type for a date range.
     * A room is available if: active, not out_of_order, and no overlapping reservation
     * with status in [CONFIRMED, CHECKED_IN].
     */
    public function getAvailability(
        Hotel $hotel,
        CarbonImmutable $checkIn,
        CarbonImmutable $checkOut,
        ?int $adults = null,
        ?int $children = null,
    ): Collection;

    /**
     * Check if a specific room type has availability for dates + occupancy.
     */
    public function isRoomTypeAvailable(
        HotelRoomType $roomType,
        CarbonImmutable $checkIn,
        CarbonImmutable $checkOut,
        int $adults = 1,
        int $children = 0,
    ): bool;

    /**
     * Get available rooms for a room type on specific dates.
     */
    public function getAvailableRooms(
        HotelRoomType $roomType,
        CarbonImmutable $checkIn,
        CarbonImmutable $checkOut,
    ): Collection;
}
```

### 3.4 API — Manager Rate Endpoints

#### ListRatesController
```
GET /v1/places/{place}/hotels/{hotel}/rates
```
List all seasonal rates. Filterable by room_type_id, season, date range.

#### ListRoomTypeRatesController
```
GET /v1/places/{place}/hotels/{hotel}/room-types/{roomType}/rates
```
Rates for a specific room type with upcoming season calendar.

### 3.5 API — Availability Endpoint (Manager + Customer)

#### CheckAvailabilityController (Manager)
```
GET /v1/places/{place}/hotels/{hotel}/availability
Query: check_in, check_out, adults, children
```
Returns per-room-type availability with pricing.

#### CheckHotelAvailabilityController (Customer)
```
GET /v1/places/{place}/hotels/{hotel}/availability
Query: check_in, check_out, adults, children
```
Returns available room types with photos, amenities, and calculated total price.

### 3.6 Resources

- `HotelSeasonalRateResource` — Rate details
- `HotelAvailabilityResource` — Room type availability with pricing

### 3.7 Form Requests

- `CheckAvailabilityRequest` — check_in, check_out (required dates, check_out > check_in), adults (int ≥ 1), children (int ≥ 0)

### 3.8 Tests

**File:** `tests/Feature/Controllers/HotelManager/RatesTest.php`

- [ ] Manager can list seasonal rates
- [ ] Manager can list rates for a specific room type
- [ ] Availability returns correct room counts
- [ ] Availability respects existing reservations (confirmed + checked-in)
- [ ] Availability respects room status (out_of_order excluded)
- [ ] Availability respects occupancy limits
- [ ] Rate engine returns seasonal rate when applicable
- [ ] Rate engine falls back to base price when no seasonal rate
- [ ] Rate engine handles multi-season stays (split across seasonal boundaries)
- [ ] Customer availability endpoint returns correct pricing (member vs non-member)

---

## Files Created/Modified

| Action | File |
|---|---|
| Create | `app/Filament/Resources/HotelResource/RelationManagers/SeasonalRatesRelationManager.php` |
| Modify | `app/Filament/Resources/HotelResource.php` — add SeasonalRatesRelationManager |
| Create | `app/Services/HotelManager/HotelRateService.php` |
| Create | `app/Services/HotelManager/HotelAvailabilityService.php` |
| Create | `app/Http/Controllers/Api/Employee/HotelManager/ListRatesController.php` |
| Create | `app/Http/Controllers/Api/Employee/HotelManager/ListRoomTypeRatesController.php` |
| Create | `app/Http/Controllers/Api/Employee/HotelManager/CheckAvailabilityController.php` |
| Create | `app/Http/Controllers/Api/Hotel/CheckHotelAvailabilityController.php` |
| Create | `app/Http/Resources/HotelManager/HotelSeasonalRateResource.php` |
| Create | `app/Http/Resources/HotelManager/HotelAvailabilityResource.php` |
| Create | `app/Http/Requests/HotelManager/CheckAvailabilityRequest.php` |
| Modify | `routes/api.php` — add rate & availability routes |
| Create | `tests/Feature/Controllers/HotelManager/RatesTest.php` |

---

## Acceptance Criteria

- [ ] Filament seasonal rates CRUD with date overlap validation
- [ ] HotelRateService correctly resolves seasonal vs base rates
- [ ] HotelRateService handles multi-season stays
- [ ] HotelAvailabilityService returns correct availability
- [ ] Availability excludes rooms with overlapping reservations
- [ ] Availability respects occupancy limits
- [ ] All API endpoints functional with Swagger annotations
- [ ] All tests pass
- [ ] Pint + PHPStan pass on new/modified files
