<?php

namespace App\Models;

use App\Models\Concerns\BelongsToBranch;
use App\Models\Concerns\HasAuditColumns;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;

class FeeChallan extends Model
{
    use BelongsToBranch;
    use HasAuditColumns;
    use SoftDeletes;

    protected $fillable = [
        'branch_id', 'challan_number', 'family_id', 'academic_session_id', 'title',
        'billing_month', 'bill_date', 'due_date',
        'total_amount', 'discount_amount', 'fine_amount', 'paid_amount', 'status', 'notes',
    ];

    protected function casts(): array
    {
        return [
            'billing_month' => 'date',
            'bill_date' => 'date',
            'due_date' => 'date',
            'total_amount' => 'decimal:2',
            'discount_amount' => 'decimal:2',
            'fine_amount' => 'decimal:2',
            'paid_amount' => 'decimal:2',
        ];
    }

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

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

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

    /** Net payable = gross − discount + fine. */
    public function getNetPayableAttribute(): float
    {
        return (float) $this->total_amount - (float) $this->discount_amount + (float) $this->fine_amount;
    }

    public function getBalanceAttribute(): float
    {
        return round($this->net_payable - (float) $this->paid_amount, 2);
    }

    /** Recompute paid_amount from payments and set the derived status. */
    public function recalculateStatus(): void
    {
        if ($this->status === 'waived') {
            return;
        }

        $paid = (float) $this->payments()->sum('amount');
        $net = $this->net_payable;

        $status = $paid <= 0 ? 'unpaid' : ($paid >= $net ? 'paid' : 'partial');

        $this->forceFill(['paid_amount' => $paid, 'status' => $status])->save();
    }

    public function scopeOutstanding(Builder $q): Builder
    {
        return $q->whereIn('status', ['unpaid', 'partial']);
    }

    public function getStatusColorAttribute(): string
    {
        return ['unpaid' => 'danger', 'partial' => 'warning', 'paid' => 'success', 'waived' => 'secondary'][$this->status] ?? 'secondary';
    }

    public static function nextNumber(int $branchId): string
    {
        $count = static::withoutGlobalScopes()->where('branch_id', $branchId)->withTrashed()->count();

        return 'CH-'.date('Y').'-'.str_pad((string) ($count + 1), 5, '0', STR_PAD_LEFT);
    }
}
