<?php

declare(strict_types=1);

namespace App\Models;

use App\Business\Product\DberpDocumentLineUnitService;
use App\Models\Concerns\HasDberpDocumentLineUnitRelations;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class DberpSalesQuoteItem extends Model
{
    use HasDberpDocumentLineUnitRelations;

    protected $table = 'dberp_sales_quote_items';

    /**
     * @var list<string>
     */
    protected $fillable = [
        'quote_id',
        'product_id',
        'product_sku_id',
        'product_sku_code',
        'product_sku_name',
        'product_sku_spec',
        'unit_id',
        'unit_name',
        'base_unit_id',
        'auxiliary_unit_id',
        'is_auxiliary_unit',
        'auxiliary_unit_quantity',
        'base_unit_quantity',
        'product_code_snapshot',
        'product_name_snapshot',
        'product_spec_snapshot',
        'external_product_id',
        'external_sku',
        'quantity',
        'unit_price',
        'line_amount',
        'discount_amount',
        'final_amount',
        'price_source_type',
        'price_source_label',
        'price_rule_id',
        'matched_unit_price',
        'reference_unit_price',
        'recent_transaction_unit_price',
        'recent_transaction_date',
        'sort_order',
        'remark',
    ];

    protected static function booted(): void
    {
        static::saving(function (self $item): void {
            $product = DberpProduct::query()->find($item->product_id);

            if ($product !== null) {
                $item->forceFill([
                    'product_code_snapshot' => $product->code,
                    'product_name_snapshot' => $product->name,
                    'product_spec_snapshot' => $product->spec_model,
                    'external_product_id' => $item->external_product_id ?: $product->external_product_id,
                    'external_sku' => $item->external_sku ?: $product->external_sku,
                ]);
            }

            DberpDocumentLineUnitService::applySnapshotsToLine($item);

            $lineAmount = (float) $item->quantity * (float) $item->unit_price;
            $discountAmount = (float) $item->discount_amount;

            $item->setAttribute('line_amount', number_format($lineAmount, 4, '.', ''));
            $item->setAttribute('final_amount', number_format(max($lineAmount - $discountAmount, 0), 4, '.', ''));
        });

        $refreshQuoteTotals = function (self $item): void {
            if ($item->quote_id === null) {
                return;
            }

            $totals = self::query()
                ->where('quote_id', $item->quote_id)
                ->selectRaw('COALESCE(SUM(quantity), 0) as total_quantity, COALESCE(SUM(line_amount), 0) as total_amount, COALESCE(SUM(discount_amount), 0) as total_discount_amount, COALESCE(SUM(final_amount), 0) as final_amount')
                ->first();

            DberpSalesQuote::query()->whereKey($item->quote_id)->update([
                'total_quantity' => round((float) ($totals?->total_quantity ?? 0), 4),
                'total_amount' => round((float) ($totals?->total_amount ?? 0), 4),
                'discount_amount' => round((float) ($totals?->total_discount_amount ?? 0), 4),
                'final_amount' => round((float) ($totals?->final_amount ?? 0), 4),
                'updated_at' => now(),
            ]);
        };

        static::saved($refreshQuoteTotals);
        static::deleted($refreshQuoteTotals);
    }

    protected function casts(): array
    {
        return [
            'quote_id' => 'integer',
            'product_id' => 'integer',
            'product_sku_id' => 'integer',
            'unit_id' => 'integer',
            'base_unit_id' => 'integer',
            'auxiliary_unit_id' => 'integer',
            'is_auxiliary_unit' => 'boolean',
            'auxiliary_unit_quantity' => 'decimal:6',
            'base_unit_quantity' => 'decimal:6',
            'quantity' => 'decimal:4',
            'unit_price' => 'decimal:4',
            'line_amount' => 'decimal:4',
            'discount_amount' => 'decimal:4',
            'final_amount' => 'decimal:4',
            'price_rule_id' => 'integer',
            'matched_unit_price' => 'decimal:4',
            'reference_unit_price' => 'decimal:4',
            'recent_transaction_unit_price' => 'decimal:4',
            'recent_transaction_date' => 'date',
            'sort_order' => 'integer',
        ];
    }

    public function quote(): BelongsTo
    {
        return $this->belongsTo(DberpSalesQuote::class, 'quote_id');
    }

    public function product(): BelongsTo
    {
        return $this->belongsTo(DberpProduct::class, 'product_id');
    }

    public function productSku(): BelongsTo
    {
        return $this->belongsTo(DberpProductSku::class, 'product_sku_id');
    }

    public function priceRule(): BelongsTo
    {
        return $this->belongsTo(DberpCustomerPriceRule::class, 'price_rule_id');
    }
}
