<?php

namespace App\Models\Returns;

use App\Models\Concerns\Auditable;
use App\Models\Concerns\BelongsToTenant;
use App\Models\Customers\Customer;
use App\Models\Lookups\Status;
use App\Models\Sales\Invoice;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;

class CreditNote extends Model
{
    use Auditable, BelongsToTenant, SoftDeletes;

    protected $fillable = [
        'cn_number', 'customer_id', 'return_id', 'claimed_invoice_id',
        'status_id', 'amount', 'applied_amount', 'note', 'issued_at', 'claimed_at',
        'voided_at', 'void_reason',
    ];

    protected function casts(): array
    {
        return [
            'amount' => 'decimal:2',
            'applied_amount' => 'decimal:2',
            'issued_at' => 'datetime',
            'claimed_at' => 'datetime',
            'voided_at' => 'datetime',
        ];
    }

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

    public function return(): BelongsTo
    {
        return $this->belongsTo(ReturnDoc::class, 'return_id');
    }

    public function claimedInvoice(): BelongsTo
    {
        return $this->belongsTo(Invoice::class, 'claimed_invoice_id');
    }

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

    /**
     * What is left on the note: its face value less everything already spent
     * against it.
     *
     * A note is a store of value that can be drawn down over more than one
     * invoice — a Rs. 5,000 note can settle Rs. 2,000 today and keep Rs. 3,000
     * for next time. `applied_amount` is the running total spent, so this is
     * the figure every "can I pay with this?" question is really asking about.
     */
    public function remainingAmount(): float
    {
        return round(max(0, (float) $this->amount - (float) $this->applied_amount), 2);
    }

    public function isFullyApplied(): bool
    {
        return $this->remainingAmount() <= 0.001;
    }

    /**
     * Notes with value left to spend: issued, not voided, not used up.
     *
     * This — not "status is issued" — is what a payment picker must offer.
     * A partly-spent note stays ISSUED (see CreditNoteService::claim()), so
     * filtering on status alone would offer a Rs. 5,000 note that has Rs. 200
     * left on it as though it were worth Rs. 5,000.
     *
     * @param  Builder<CreditNote>  $query
     * @return Builder<CreditNote>
     */
    public function scopeSpendable(Builder $query): Builder
    {
        return $query
            ->whereHas('status', fn ($q) => $q->where('code', Status::ISSUED))
            ->whereRaw('(amount - COALESCE(applied_amount, 0)) > 0.001');
    }

    /** "CN-2026001 — Rs. 3,000.00 left of Rs. 5,000.00" */
    public function pickerLabel(): string
    {
        $remaining = $this->remainingAmount();
        $face = (float) $this->amount;

        if (abs($remaining - $face) < 0.001) {
            return $this->cn_number.' — Rs. '.number_format($face, 2);
        }

        return $this->cn_number.' — Rs. '.number_format($remaining, 2)
            .' left of Rs. '.number_format($face, 2);
    }
}
