<?php

namespace App\Models;

use App\Enums\BookingStatus;
use App\Enums\InvoiceStatus;
use App\Models\Concerns\HasAttachments;
use Database\Factories\BookingFactory;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;

class Booking extends Model
{
    /** @use HasFactory<BookingFactory> */
    use HasAttachments, HasFactory, SoftDeletes;

    /**
     * @var list<string>
     */
    protected $fillable = [
        'booking_number',
        'customer_id',
        'contact_name',
        'contact_phone',
        'contact_email',
        'event_name',
        'event_type_id',
        'description',
        'event_start',
        'event_end',
        'guest_count',
        'billable_days',
        'billable_hours',
        'seating_arrangement',
        'coordinator_id',
        'customer_notes',
        'internal_notes',
        'catering_requirements',
        'av_requirements',
        'decorations_requirements',
        'signage_requirements',
        'security_requirements',
        'other_requirements',
        'status',
        'billable_days_override_reason',
        'billable_hours_override_reason',
        'subtotal',
        'discount_amount',
        'service_charge_amount',
        'tax_amount',
        'grand_total',
        'amount_paid',
        'outstanding_balance',
    ];

    /**
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'customer_id' => 'integer',
            'event_type_id' => 'integer',
            'event_start' => 'datetime',
            'event_end' => 'datetime',
            'guest_count' => 'integer',
            'billable_days' => 'integer',
            'billable_hours' => 'integer',
            'coordinator_id' => 'integer',
            'status' => BookingStatus::class,
            'subtotal' => 'decimal:2',
            'discount_amount' => 'decimal:2',
            'service_charge_amount' => 'decimal:2',
            'tax_amount' => 'decimal:2',
            'grand_total' => 'decimal:2',
            'amount_paid' => 'decimal:2',
            'outstanding_balance' => 'decimal:2',
        ];
    }

    /**
     * @return BelongsTo<Customer, $this>
     */
    public function customer(): BelongsTo
    {
        return $this->belongsTo(Customer::class);
    }

    /**
     * @return BelongsTo<EventType, $this>
     */
    public function eventType(): BelongsTo
    {
        return $this->belongsTo(EventType::class);
    }

    /**
     * @return BelongsTo<User, $this>
     */
    public function coordinator(): BelongsTo
    {
        return $this->belongsTo(User::class, 'coordinator_id');
    }

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

    /**
     * @return HasMany<BookingItem, $this>
     */
    public function items(): HasMany
    {
        return $this->hasMany(BookingItem::class)->orderBy('sort_order');
    }

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

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

    public function isEarlyStatus(): bool
    {
        return in_array($this->status, [
            BookingStatus::Enquiry,
            BookingStatus::Provisional,
            BookingStatus::AwaitingApproval,
        ], true);
    }

    /**
     * @param  Builder<Booking>  $query
     * @return Builder<Booking>
     */
    public function scopeHasIssuedInvoice(Builder $query): Builder
    {
        return $query->whereHas('invoices', function (Builder $invoiceQuery): void {
            $invoiceQuery->where(function (Builder $inner): void {
                $inner->whereIn('status', [
                    InvoiceStatus::Issued,
                    InvoiceStatus::Due,
                    InvoiceStatus::PartiallyPaid,
                    InvoiceStatus::Paid,
                    InvoiceStatus::Overdue,
                ])->orWhereNotNull('issued_at');
            });
        });
    }
}
