<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Transaction extends Model
{
    use HasFactory;

    public const TYPE_BUY = 'buy';
    public const TYPE_SELL = 'sell';
    public const TYPE_BORROW = 'borrow';
    public const TYPE_SETTLEMENT = 'settlement';
    public const TYPE_OPENING_BALANCE = 'opening_balance';
    public const TYPE_ADJUSTMENT = 'adjustment';

    protected $fillable = [
        'type',
        'currency_id',
        'quantity',
        'rate',
        'payment_amount',
        'payment_currency_id',
        'payment_account_id',
        'handling_fee',
        'fee_currency',
        'account_id',
        'agent_id',
        'borrow_settled_at',
        'borrow_settlement_id',
        'exchange_profit',
        'total_profit',
        'is_pending',
        'description',
    ];

    protected $casts = [
        'quantity' => 'decimal:4',
        'rate' => 'decimal:4',
        'payment_amount' => 'decimal:4',
        'handling_fee' => 'decimal:4',
        'exchange_profit' => 'decimal:4',
        'total_profit' => 'decimal:4',
        'is_pending' => 'boolean',
        'borrow_settled_at' => 'datetime',
    ];

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

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

    public function paymentCurrency(): BelongsTo
    {
        return $this->belongsTo(Currency::class, 'payment_currency_id');
    }

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

    public function agentBalance(): \Illuminate\Database\Eloquent\Relations\HasOne
    {
        return $this->hasOne(AgentBalance::class, 'transaction_id');
    }

    public function settlement(): BelongsTo
    {
        return $this->belongsTo(Transaction::class, 'borrow_settlement_id');
    }

    /**
     * Reverses the balance effects of this transaction on the related accounts.
     */
    public function reverseBalanceEffects(): void
    {
        switch ($this->type) {
            case self::TYPE_BUY:
                // Reverse Buy: Deduct from target, restore to payment
                if ($this->account && !$this->is_pending) {
                    $this->account->decrement('balance', (float) $this->quantity + (float) $this->handling_fee);
                }
                $paymentAccount = Account::find($this->payment_account_id);
                if ($paymentAccount) {
                    $paymentAccount->increment('balance', (float) $this->payment_amount);
                }
                break;

            case self::TYPE_SELL:
                // Reverse Sell: Restore to source, deduct from payment/target
                if ($this->account) {
                    $this->account->increment('balance', (float) $this->quantity);
                }
                $paymentAccount = Account::find($this->payment_account_id);
                if ($paymentAccount && !$this->is_pending) {
                    $paymentAccount->decrement('balance', (float) $this->payment_amount + (float) $this->handling_fee);
                }
                break;

            case self::TYPE_ADJUSTMENT:
                // Reverse Adjustment: Deduct the adjusted quantity from the account
                if ($this->account) {
                    $this->account->decrement('balance', (float) $this->quantity);
                }
                break;

            case self::TYPE_BORROW:
                // Reverse Borrow: Deduct from target account
                if ($this->account) {
                    $this->account->decrement('balance', (float) $this->quantity);
                }
                break;

            case self::TYPE_SETTLEMENT:
                // Reverse Settlement: Restore to payment account, mark borrow as unsettled
                $paymentAccount = Account::find($this->payment_account_id);
                if ($paymentAccount) {
                    $paymentAccount->increment('balance', (float) $this->payment_amount);
                }
                // Find the borrow that was settled by this transaction
                $borrow = self::where('borrow_settlement_id', $this->id)->first();
                if ($borrow) {
                    $borrow->update([
                        'borrow_settled_at' => null,
                        'borrow_settlement_id' => null,
                    ]);
                }
                break;

            case self::TYPE_OPENING_BALANCE:
                // Reverse Opening Balance: Deduct from account
                if ($this->account) {
                    $this->account->decrement('balance', (float) $this->quantity);
                }
                break;
        }
    }
}
