<?php

namespace App\Models;

use App\Enums\InvestmentTransactionType;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

#[Fillable([
    'investment_id',
    'beneficiary_user_id',
    'type',
    'amount',
    'balance_after',
    'platform_month_accrual_id',
    'investment_month_index',
    'applied_percent',
    'accrual_on',
    'gain_period_start',
    'gain_period_end',
    'withdrawal_request_id',
    'referral_level',
    'referral_source_transaction_id',
    'admin_note',
    'created_by_user_id',
    'reversed_at',
    'reversed_by_user_id',
    'reversal_of_transaction_id',
])]
class InvestmentTransaction extends Model
{
    /**
     * @return BelongsTo<Investment, InvestmentTransaction>
     */
    public function investment(): BelongsTo
    {
        return $this->belongsTo(Investment::class);
    }

    /**
     * @return BelongsTo<PlatformMonthAccrual, InvestmentTransaction>
     */
    public function platformMonthAccrual(): BelongsTo
    {
        return $this->belongsTo(PlatformMonthAccrual::class, 'platform_month_accrual_id');
    }

    /**
     * @return BelongsTo<WithdrawalRequest, InvestmentTransaction>
     */
    public function withdrawalRequest(): BelongsTo
    {
        return $this->belongsTo(WithdrawalRequest::class, 'withdrawal_request_id');
    }

    /**
     * @return BelongsTo<User, InvestmentTransaction>
     */
    public function beneficiary(): BelongsTo
    {
        return $this->belongsTo(User::class, 'beneficiary_user_id');
    }

    /**
     * @return BelongsTo<InvestmentTransaction, InvestmentTransaction>
     */
    public function referralSourceTransaction(): BelongsTo
    {
        return $this->belongsTo(self::class, 'referral_source_transaction_id');
    }

    /**
     * @return BelongsTo<User, InvestmentTransaction>
     */
    public function createdBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'created_by_user_id');
    }

    /**
     * @return BelongsTo<User, InvestmentTransaction>
     */
    public function reversedBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'reversed_by_user_id');
    }

    /**
     * @return BelongsTo<InvestmentTransaction, InvestmentTransaction>
     */
    public function reversalOf(): BelongsTo
    {
        return $this->belongsTo(self::class, 'reversal_of_transaction_id');
    }

    /**
     * Movimientos visibles en el libro del usuario: los de sus inversiones (sin bonos a terceros)
     * y los bonos de referido donde él es el beneficiario.
     *
     * @param  Builder<InvestmentTransaction>  $query
     * @return Builder<InvestmentTransaction>
     */
    public function scopeVisibleInUserLedger(Builder $query, int $userId): Builder
    {
        $excludedBeneficiaryTypes = [
            InvestmentTransactionType::ReferralManualDirectAdjustment->value,
            InvestmentTransactionType::ReferralManualIndirectAdjustment->value,
        ];

        return $query->where(function (Builder $inner) use ($userId, $excludedBeneficiaryTypes): void {
            $inner
                ->where(function (Builder $beneficiary) use ($userId, $excludedBeneficiaryTypes): void {
                    $beneficiary
                        ->where('beneficiary_user_id', $userId)
                        ->whereNotIn('type', $excludedBeneficiaryTypes);
                })
                ->orWhere(function (Builder $owned) use ($userId): void {
                    $owned
                        ->whereHas('investment', fn (Builder $investmentQuery) => $investmentQuery->where('user_id', $userId))
                        ->whereNull('beneficiary_user_id')
                        ->where('type', '!=', InvestmentTransactionType::AdminAdjustmentReversal->value);
                });
        });
    }

    protected function casts(): array
    {
        return [
            'type' => InvestmentTransactionType::class,
            'amount' => 'decimal:2',
            'balance_after' => 'decimal:2',
            'applied_percent' => 'decimal:4',
            'accrual_on' => 'date',
            'gain_period_start' => 'date',
            'gain_period_end' => 'date',
            'referral_level' => 'integer',
            'reversed_at' => 'datetime',
        ];
    }
}
