<?php

namespace App\Models;

use App\Enums\OrderStatus;
use Database\Factories\OrderFactory;
use DateTimeInterface;
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\Relations\HasOne;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Carbon;
use Spatie\Browsershot\Browsershot;
use Spatie\LaravelPdf\Facades\Pdf;

class Order extends Model
{
    /** @use HasFactory<OrderFactory> */
    use HasFactory, SoftDeletes;

    protected $fillable = [
        'customer_id',
        'contact_id',
        'internal_po',
        'customer_po',
        'order_date',
        'order_type',
        'status',
        'due_date',
        'notes',
        'rush',
        'repeat',
        'new_art',
        'event',
        'digitizing',
        'garments',
        'supplied_file',
    ];

    protected $casts = [
        'status' => OrderStatus::class,
        //        'order_attributes' => 'array',
    ];

    public static function boot(): void
    {
        parent::boot();

        static::created(function ($model) {
            $model->attributes['internal_po'] = $model->generateInternalPo($model->id);
            $model->save();
        });
    }

    public function dueDatePdf(): string
    {
        return Carbon::createFromDate($this->due_date)->format('M d, Y');
    }

    public function orderDatePdf(): string
    {
        return Carbon::createFromDate($this->order_date)->format('M d, Y');
    }

    public function generateInternalPo(int $id): string
    {
        $po   = str_pad(strval($id), 4, '0', STR_PAD_LEFT);
        $year = date('y');

        return 'TN'.$year.'-'.$po;
    }

    public function totalProductQuantity(): int
    {
        $total = 0;

        foreach ($this->orderProducts as $product) {
            $total += $product->totalQuantity();
        }

        return $total;
    }

    public function totalServicePrice(): string
    {
        $total = 0;

        foreach ($this->productServices as $service) {
            $total += $service->amount * $service->amount_price;
        }

        return number_format($total, 2);
    }

    public function active(): bool
    {
        if ($this->status == OrderStatus::APPROVED
            || $this->status == OrderStatus::PRODUCTION) {
            return true;
        }

        return false;
    }

    public function generatePdf(): \Illuminate\Foundation\Application|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
    {
        Pdf::view('pdf.order', ['order' => $this])
            ->withBrowsershot(function (Browsershot $browsershot) {
                $browsershot->noSandbox();
            })
            ->margins(8, 8, 15, 8)
            ->footerView('pdf.order-footer', ['order' => $this])
            ->save('order.pdf');

        return redirect('order.pdf');
    }

    /**
     * @param  Builder<Order>  $query
     * @return Builder<Order>
     */
    public function scopeActive(Builder $query): Builder
    {
        return $query->where('status', 'approved')
            ->orWhere('status', 'production');
    }

    /**
     * @param  Builder<Order>  $query
     * @return Builder<Order>
     */
    public function scopeFinished(Builder $query): Builder
    {
        return $query->where('status', 'shipped')
            ->orWhere('status', 'completed');
    }

    /**
     * @param  Builder<Order>  $query
     * @return Builder<Order>
     */
    public function scopeInvoiced(Builder $query): Builder
    {
        return $query->where('status', 'invoiced');
    }

    /**
     * @param  Builder<Order>  $query
     * @return Builder<Order>
     */
    public function scopeRush(Builder $query): Builder
    {
        return $query->where('rush', true);
    }

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

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

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

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

    public function packingSlips(): HasMany
    {
        return $this->hasMany(PackingSlip::class);
    }

    public function quote(): HasOne
    {
        return $this->hasOne(Quote::class);
    }

    protected function serializeDate(DateTimeInterface $date): string
    {
        return $date->format('Y-m-d');
    }
}