<?php

namespace App\Domains\Ticket\Models;

use App\Domains\Catalog\Models\AttributeOption;
use App\Domains\Event\Models\EventDate;
use App\Domains\Ticket\Enums\ValidityTimeType;
use Carbon\CarbonImmutable;
use Carbon\CarbonInterface;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;

#[Fillable([
    'type',
    'start_time',
    'end_time',
    'fixed_starts_at',
    'fixed_expires_at',
])]
class ValidityTime extends Model
{
    use HasFactory;

    protected function casts(): array
    {
        return [
            'type' => ValidityTimeType::class,
            'fixed_starts_at' => 'datetime',
            'fixed_expires_at' => 'datetime',
        ];
    }

    /** @return HasMany<AttributeOption, $this> */
    public function attributeOptions(): HasMany
    {
        return $this->hasMany(AttributeOption::class);
    }

    /** @return HasOne<EventDate, $this> */
    public function eventDate(): HasOne
    {
        return $this->hasOne(EventDate::class);
    }

    public function startsAt(
        ?CarbonInterface $at = null,
    ): ?CarbonInterface {
        if ($this->type === ValidityTimeType::FixedWindow) {
            return $this->fixed_starts_at;
        }

        return $this->atCurrentDate($this->start_time, $at);
    }

    public function expiresAt(
        ?CarbonInterface $at = null,
    ): ?CarbonInterface {
        if ($this->type === ValidityTimeType::FixedWindow) {
            return $this->fixed_expires_at;
        }

        return $this->atCurrentDate($this->end_time, $at);
    }

    public function isValid(
        ?CarbonInterface $at = null,
    ): bool {
        $at ??= now();
        $startsAt = $this->startsAt($at);
        $expiresAt = $this->expiresAt($at);

        return ($startsAt === null || $startsAt->lessThanOrEqualTo($at))
            && ($expiresAt === null || $expiresAt->greaterThan($at));
    }

    private function atCurrentDate(
        ?string $time,
        ?CarbonInterface $at,
    ): ?CarbonInterface {
        if ($time === null) {
            return null;
        }

        $at ??= now();
        $localDate = CarbonImmutable::instance($at)
            ->format('Y-m-d');

        return CarbonImmutable::parse($localDate.' '.$time);
    }
}
