<?php

namespace App\Models;

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 SupplierInvoice extends Model
{
    use HasFactory, SoftDeletes;

    protected $fillable = [
        'supplier_id',
        'branch_id',
        'user_id',
        'purchase_order_id',
        'invoice_number',
        'our_reference',
        'invoice_date',
        'due_date',
        'subtotal',
        'discount_amount',
        'tax_amount',
        'total_amount',
        'paid_amount',
        'remaining_amount',
        'payment_type',
        'status',
        'notes',
    ];

    protected $casts = [
        'invoice_date'    => 'date',
        'due_date'        => 'date',
        'subtotal'        => 'decimal:2',
        'discount_amount' => 'decimal:2',
        'tax_amount'      => 'decimal:2',
        'total_amount'    => 'decimal:2',
        'paid_amount'     => 'decimal:2',
        'remaining_amount'=> 'decimal:2',
    ];

    public const STATUS_DRAFT    = 'draft';
    public const STATUS_UNPAID   = 'unpaid';
    public const STATUS_PARTIAL  = 'partial';
    public const STATUS_PAID     = 'paid';
    public const STATUS_OVERDUE  = 'overdue';
    public const STATUS_CANCELLED= 'cancelled';

    public const TYPE_CREDIT = 'credit';
    public const TYPE_CASH   = 'cash';

    public function supplier(): BelongsTo
    {
        return $this->belongsTo(Supplier::class);
    }

    public function branch(): BelongsTo
    {
        return $this->belongsTo(Branch::class);
    }

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    public function purchaseOrder(): BelongsTo
    {
        return $this->belongsTo(PurchaseOrder::class);
    }

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

    public function payments(): HasMany
    {
        return $this->hasMany(SupplierPayment::class, 'supplier_id', 'supplier_id');
    }

    public function scopeOverdue($query)
    {
        return $query->where('due_date', '<', now()->toDateString())
                     ->whereIn('status', [self::STATUS_UNPAID, self::STATUS_PARTIAL]);
    }

    public function scopeCredit($query)
    {
        return $query->where('payment_type', self::TYPE_CREDIT);
    }

    public function recalculateTotals(): void
    {
        $subtotal = $this->items()->sum('total_price');
        $total    = $subtotal - $this->discount_amount + $this->tax_amount;
        $remaining= $total - $this->paid_amount;

        $this->update([
            'subtotal'         => $subtotal,
            'total_amount'     => $total,
            'remaining_amount' => max(0, $remaining),
        ]);
    }

    public function applyPayment(float $amount): void
    {
        $newPaid      = (float) $this->paid_amount + $amount;
        $newRemaining = max(0, (float) $this->total_amount - $newPaid);
        $newStatus    = $newRemaining <= 0 ? self::STATUS_PAID : self::STATUS_PARTIAL;

        $this->update([
            'paid_amount'      => $newPaid,
            'remaining_amount' => $newRemaining,
            'status'           => $newStatus,
        ]);
    }

    public function applyCreditNote(float $amount): void
    {
        $newRemaining = max(0, (float) $this->remaining_amount - $amount);
        $newStatus    = $newRemaining <= 0 ? self::STATUS_PAID : $this->status;

        $this->update([
            'remaining_amount' => $newRemaining,
            'status'           => $newStatus,
        ]);
    }

    public function isOverdue(): bool
    {
        return $this->due_date < now()->toDateString()
            && in_array($this->status, [self::STATUS_UNPAID, self::STATUS_PARTIAL]);
    }

    public static function generateInvoiceNumber(): string
    {
        $prefix = 'SINV-' . date('Ymd');
        $last   = static::where('invoice_number', 'like', $prefix . '%')
                        ->orderBy('invoice_number', 'desc')
                        ->first();

        $next = $last ? ((int) substr($last->invoice_number, -4)) + 1 : 1;
        return $prefix . '-' . str_pad($next, 4, '0', STR_PAD_LEFT);
    }
}
