<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Facades\DB;
use InvalidArgumentException;
use RuntimeException;
use Exception;

class CustomerBalance extends Model
{

    protected $table = 'ac_customer_balances';
    protected $fillable = [
        'customer_id',
        'current_balance',
        'total_paid',
        'total_refunded',
        'last_transaction_date',
        'last_transaction_type',
        'last_transaction_amount',
        'notes'
    ];

    protected $casts = [
        'current_balance' => 'decimal:2',
        'total_paid' => 'decimal:2',
        'total_refunded' => 'decimal:2',
        'last_transaction_date' => 'datetime',
        'last_transaction_amount' => 'decimal:2',
    ];

    // Relationships
    public function customer(): BelongsTo
    {
        return $this->belongsTo(Customer::class, 'customer_id');
    }

    public function transactions(): HasMany
    {
        return $this->hasMany(CustomerBalanceTransaction::class, 'balance_id');
    }

    // Scopes
    public function scopePositiveBalance($query)
    {
        return $query->where('current_balance', '>', 0);
    }

    public function scopeNegativeBalance($query)
    {
        return $query->where('current_balance', '<', 0);
    }

    public function scopeZeroBalance($query)
    {
        return $query->where('current_balance', 0);
    }

    // Methods
    public function getNetBalanceAttribute(): float
    {
        return $this->current_balance - $this->total_debit;
    }
    public function getBalanceClassAttribute(): string
    {
        if ($this->net_balance > 0) {
            return 'success'; // له رصيد
        }

        if ($this->net_balance < 0) {
            return 'danger'; // عليه
        }

        return 'primary';
    }
    public function getBalanceStatusAttribute(): string
    {
        if ($this->net_balance > 0) {
            return __('He has credit');
        }

        if ($this->net_balance < 0) {
            return __('He owes credit');
        }

        return __('He is balanced');
    }

    public function updateBalance($amount, $type, $referenceId, $description, $createdBy): CustomerBalanceTransaction
    {
        return DB::transaction(function () use ($amount, $type, $referenceId, $description, $createdBy) {

            if ($amount <= 0) {
                throw new InvalidArgumentException('المبلغ لازم يكون أكبر من صفر');
            }

            $balance = self::where('id', $this->id)->lockForUpdate()->first();

            $oldBalance = $balance->current_balance;

            switch ($type) {
                case 'deposit':
                    if ($balance->total_debit > 0) {
                        if ($amount >= $balance->total_debit) {
                            $amountAfterDebt = $amount - $balance->total_debit;
                            $balance->total_debit = 0;
                            $newBalance = $oldBalance + $amountAfterDebt;
                        } else {
                            $balance->total_debit -= $amount;
                            $newBalance = $oldBalance;
                        }
                    } else {
                        $newBalance = $oldBalance + $amount;
                    }

                    $balance->total_paid += $amount;
                    break;

                case 'refund':
                    $newBalance = $oldBalance - $amount;
                    $balance->total_refunded += $amount;
                    break;

                case 'expense':
                    if ($amount > $oldBalance) {
                        throw new \RuntimeException('الرصيد غير كافي');
                    }
                    $newBalance = $oldBalance - $amount;
                    break;

                case 'debit':
                    $newBalance = $oldBalance - $amount;
                    $balance->total_debit += $amount;
                    break;

                case 'adjustment':
                    $adjustment = $amount - $oldBalance;
                    $newBalance = $amount;

                    if ($adjustment > 0) {
                        $balance->total_paid += $adjustment;
                    } else {
                        $balance->total_refunded += abs($adjustment);
                    }
                    break;

                default:
                    throw new InvalidArgumentException("نوع الحركة {$type} غير مدعوم");
            }

            $transaction = $balance->transactions()->create([
                'customer_id' => $balance->customer_id,
                'transaction_type' => $type,
                'amount' => $amount,
                'previous_balance' => $oldBalance,
                'new_balance' => $newBalance,
                'reference_id' => $referenceId,
                'description' => $description,
                'created_by' => $createdBy,
            ]);

            $balance->current_balance = $newBalance;
            $balance->last_transaction_date = now();
            $balance->last_transaction_type = $type;
            $balance->last_transaction_amount = $amount;
            $balance->save();

            return $transaction;
        });
    }

    public static function getOrCreateForCustomer($customerId)
    {
        return self::firstOrCreate(
            ['customer_id' => $customerId],
            [
                'current_balance' => 0,
                'total_paid' => 0,
                'total_refunded' => 0,
            ]
        );
    }
}
