<?php

namespace App\Console\Commands;

use App\Models\AvailabilityRule;
use App\Models\User;
use App\Services\Client\ItemAvailabilityService;
use Carbon\Carbon;
use Carbon\CarbonPeriod;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

use function Laravel\Prompts\info;

class TestCode extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'test:code';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Execute the console command.
     */
    public function handle()
    {
        $start = microtime(true);

        $checkIn = '2026-04-2';
        $checkOut = '2026-04-06';

        // Active is the default status of the item not rule
        $defaultAvailable = true;
        $allow_select = false; // this define the the use can select date or not


        // The rule is alave filred one. if default values avabile all rules are come here is blocked one not available
        // $rules = [
        //     ['start_date' => '2026-03-1', 'end_date'   => '2026-03-2'],
        //     ['start_date' => '2026-03-2', 'end_date'   => '2026-03-5'],
        //     ['start_date' => '2026-03-7', 'end_date'   => '2026-03-10'],
        // ];


        // // 01 - Define and cnvert dates
        // $checkIn = Carbon::parse($checkIn)->startOfDay();
        // $checkOut = Carbon::parse($checkOut)->subDay()->startOfDay();

        // $result = $this->isDateInRange_v1($rules, $checkIn, $checkOut, $defaultAvailable);
        // dump($result);

        // $result = $this->getAvailableDates_v1($rules, $checkIn, $checkOut, $defaultAvailable);

        // $ruleStart = Carbon::parse($rule['start_date'])->startOfDay();
        // $ruleEnd = Carbon::parse($rule['end_date'])->startOfDay();

        // // 03 - Check rule is in range if allow other vise get dates list that are available
        // $result = null;
        // // if ($allow_select) {
        // $result = $this->getAvailableDates($ruleStart, $ruleEnd, $checkIn, $checkOut, $active);
        // // } else {
        // dump($result);
        // $result = $this->isDateInRange($ruleStart, $ruleEnd, $checkIn, $checkOut, $active);
        // // }

        $rules = AvailabilityRule::all();
        $rulesArray = $rules->toArray();

        // $rules = [
        //     ['pattern_type' => 'weekly', 'day_of_week' => 4],  // every Monday
        //     ['pattern_type' => 'monthly', 'day_of_month' => 15],
        //     ['pattern_type' => 'yearly', 'month_of_year' => 12, 'day_of_month' => 25],
        //     ['pattern_type' => 'date_range', 'start_date' => '2026-03-20', 'end_date' => '2026-03-22'],
        // ];

        $result = ItemAvailabilityService::check($rulesArray, $checkIn, $checkOut, $defaultAvailable);

        dump($result);

        // -----------------------------------------------------------< runtime
        $end = microtime(true);
        $duration = ($end - $start) * 1000; // convert to ms
        $this->info("Execution time: {$duration} ms");
    }




    // // Check full rage of date is availbe or not
    // function isDateInRange(Carbon $ruleStart, Carbon $ruleEnd,  Carbon $checkIn, Carbon $checkOut, bool $defaultAvailable): bool
    // {
    //     // ANY overlap check
    //     $overlaps = $checkIn->lte($ruleEnd) && $checkOut->gte($ruleStart);

    //     // Check if FULL booking is inside rule
    //     $fullyInside  = $checkIn->gte($ruleStart) && $checkOut->lte($ruleEnd);

    //     if ($defaultAvailable) {
    //         // BLOCK mode → must be completely OUTSIDE
    //         return !$overlaps;
    //     } else {
    //         // AVAILABLE mode → must be completely INSIDE
    //         return $fullyInside;
    //     }
    // }

    // // mode ? available : blocked
    // function getAvailableDates(Carbon $ruleStart, Carbon $ruleEnd, Carbon $checkIn, Carbon $checkOut, bool $defaultAvailable): array
    // {
    //     $dates = [];
    //     for ($date = $checkIn->copy(); $date->lte($checkOut); $date->addDay()) {
    //         $inRange = $date->gte($ruleStart) && $date->lte($ruleEnd);
    //         $dates[] = $defaultAvailable !== $inRange ? $date->toDateString() : null;
    //     }
    //     return $dates;
    // }


    // Is EVERY DAY covered by ANY rule? / “All-or-nothing” for the booking period
    // Check if all days in the check-in → check-out period are available, considering the rules and the default availability.
    function isDateInRange_v1(array $rules,  Carbon $checkIn, Carbon $checkOut, bool $defaultAvailable): bool
    {
        for ($date = $checkIn->copy(); $date->lte($checkOut); $date->addDay()) {
            $covered = $defaultAvailable; // start with default

            foreach ($rules as $rule) {
                $ruleStart = Carbon::parse($rule['start_date'])->startOfDay();
                $ruleEnd = Carbon::parse($rule['end_date'])->startOfDay();

                $is_inside = $date->gte($ruleStart) && $date->lte($ruleEnd);

                if ($is_inside) {
                    $covered = !$defaultAvailable; // flip default if inside any rule
                    break;
                }
            }

            if (!$covered) {
                return false; // ❌ any uncovered day → fail immediately
            }
        }
        return true; // ✅ all days covered
    }

    // “Per-day” availability
    // Return an array of available dates individually for each day, marking null if blocked/unavailable.
    function getAvailableDates_v1(array $rules, Carbon $checkIn, Carbon $checkOut, bool $defaultAvailable): array
    {
        $dates = [];

        // Loop all date of rage and get available dates
        for ($date = $checkIn->copy(); $date->lte($checkOut); $date->addDay()) {

            $availble = $defaultAvailable;

            // Loop for all rule related to the item and check each one by one
            foreach ($rules as $rule) {
                $ruleStart = Carbon::parse($rule['start_date'])->startOfDay();
                $ruleEnd = Carbon::parse($rule['end_date'])->startOfDay();

                // when default is blocked, if the date is one of rule inside that mean the date is available bcz all rulse are availbe ones
                // when default is active,  if the date is one of rule inside that mean the date is blocked.  bcz the all rulse are blocked ones
                $inRange = $date->gte($ruleStart) && $date->lte($ruleEnd);
                if ($inRange) {
                    $availble = $defaultAvailable !== $inRange;
                    break;
                }
            }

            $dates[] = $availble ? $date->toDateString() : null;
        }

        return $dates;
    }
}
