<?php

namespace App\Services\Client;

use Carbon\Carbon;
use App\Models\Room;
use App\Models\PriceModifier;

class PricingService
{
    // calculate for the current price
    // public function nightPrice(Room $room, Carbon $date, $modifiers, $category)
    // {
    //     // Base price or override
    //     $basePrice = $category->base_price ?? 0;
    //     $price = ($room->price_override > 0) ? $room->price_override : $basePrice;

    //     foreach ($modifiers as $modifier) {

    //         if (!$this->modifierApplies($modifier, $room, $date)) {
    //             continue;
    //         }

    //         $amount = $modifier->calculation === 'percent'
    //             ? $price * ($modifier->value / 100)
    //             : $modifier->value;

    //         if ($modifier->operation === 'add') {
    //             $price += $amount;
    //         } else {
    //             $price -= $amount;
    //         }
    //     }

    //     return round($price, 3);
    // }

    // calculate for the base price, not the current price
    public function nightPrice(Room $room, Carbon $date, $modifiers, $category)
    {
        $basePrice = ($room->price_override > 0) ? $room->price_override : ($category->base_price ?? 0);
        $price = $basePrice;

        foreach ($modifiers as $modifier) {
            if (!$this->modifierApplies($modifier, $room, $date)) continue;

            // Percent modifiers apply on base price
            $amount = $modifier->calculation === 'percent' ? $basePrice * ($modifier->value / 100) : $modifier->value;
            $price += ($modifier->operation === 'add') ? $amount : -$amount;
        }

        return round($price, 3);
    }

    private function modifierApplies($modifier, Room $room, Carbon $date)
    {
        // Check if modifier is attached to room or category
        $appliesToRoom = $modifier->rooms->contains($room->id);
        $appliesToCategory = $modifier->categories->contains($room->room_category_id);
        if (!$appliesToRoom && !$appliesToCategory) return false;

        // Handle date range
        $start = $modifier->start_date ? Carbon::parse($modifier->start_date) : null;
        $end = $modifier->end_date ? Carbon::parse($modifier->end_date) : null;

        // Apply if:
        // 1. No start and no end => always applies
        // 2. Only start => date >= start
        // 3. Only end => date <= end
        // 4. Both => date between start and end (inclusive)
        if ($start && $end) {
            if (!$date->between($start, $end)) return false;
        } elseif ($start && !$end) {
            if ($date->lt($start)) return false;
        } elseif (!$start && $end) {
            if ($date->gt($end)) return false;
        }

        // Type check
        switch ($modifier->type) {
            case 'all':
                return true;
            case 'weekday':
                return $date->isWeekday();
            case 'weekend':
                return $date->isWeekend();
            case 'custom':
                $days = is_string($modifier->custom_days) ? json_decode($modifier->custom_days, true) : (array) $modifier->custom_days;
                return in_array($date->dayOfWeek, $days);
            default:
                return false;
        }
    }

    public function roomDailyPrices(Room $room, $checkIn, $checkOut, $category)
    {
        $modifiers = PriceModifier::with(['rooms:id', 'categories:id'])->orderBy('priority')->get();

        $date = Carbon::parse($checkIn);
        $end = Carbon::parse($checkOut);

        $dailyPrices = [];

        while ($date->lt($end)) {

            $price = $this->nightPrice($room, $date, $modifiers, $category);

            // 🎯 store each day's data
            $dailyPrices[] = [
                'date' => $date->toDateString(),
                'price' => round($price, 2)
            ];

            $date->addDay();
        }

        return $dailyPrices;
    }

    public function calendar(Room $room, $start, $end, $category)
    {
        $modifiers = PriceModifier::with(['rooms:id', 'categories:id'])->orderBy('priority')->get();

        $prices = [];
        $date = Carbon::parse($start);
        $endDate = Carbon::parse($end);

        while ($date->lte($endDate)) {
            $prices[$date->toDateString()] = $this->nightPrice($room, $date, $modifiers, $category);
            $date->addDay();
        }

        return $prices;
    }

    public function availableCalendar(Room $room, $start, $end, $category)
    {
        $modifiers = PriceModifier::with(['rooms:id', 'categories:id'])
            ->orderBy('priority')
            ->get();

        $calendar = [];

        $date = Carbon::parse($start)->max(Carbon::today());
        $endDate = Carbon::parse($end)->endOfDay();
        $today = Carbon::today();

        // never allow past dates
        $date = $date->max($today);

        while ($date->lte($endDate)) {

            $isBooked = $room->availabilities()
                ->where('status', '!=', 'available')
                ->where('start_date', '<=', $date->toDateString())
                ->where('end_date', '>=', $date->toDateString())
                ->exists();

            if (!$isBooked) {
                $calendar[$date->toDateString()] =
                    $this->nightPrice($room, $date, $modifiers, $category);
            }

            $date->addDay();
        }

        return $calendar;
    }
}
