<?php

namespace App\Models;

use App\Support\Currency;
use App\Traits\VisibleToAdmin;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Account extends Model
{
    use HasFactory;
    use VisibleToAdmin;

    // This tells the trait how to reach the user who controls visibility
    protected function adminVisibilityRelation(): string
    {
        return 'profile.user';
    }
    protected $fillable = [
        'profile_id',
        'account_number',
        'bank_account_type',
        'balance',
        'per_transaction_limit',
        'daily_transaction_limit',
        'monthly_transaction_limit',
        'is_primary',
        'is_active'
    ];

    // Cast balances as decimal for accurate calculations
    protected $casts = [
        'balance' => 'string',
        'per_transaction_limit' => 'decimal:2',
        'daily_transaction_limit' => 'decimal:2',
        'monthly_transaction_limit' => 'decimal:2',
        'is_primary' => 'boolean',
        'is_active' => 'boolean',
    ];
    public function getMaskedAccountNumberAttribute(): string
    {
        return str_repeat('*', max(strlen($this->account_number) - 4, 0))
            . substr($this->account_number, -4);
    }

    /**
     * Boot method to handle model events
     */
    protected static function booted()
    {
        static::creating(function ($account) {
            // Auto-generate account number if not already set
            if (empty($account->account_number)) {
                $account->account_number = self::generateAccountNumber($account->bank_account_type);
            }
        });
    }

    /**
     * Generate a unique numeric account number
     *
     * Format: [type_code][8 random digits]
     * Example: Savings (101) -> 10112345678
     */
    protected static function generateAccountNumber(string $type = null): string
    {
        $accountTypes = config('bank.account_types');

        // Default type code if not found
        $typeCode = '999';

        if ($type && isset($accountTypes[$type]) && isset($accountTypes[$type]['code'])) {
            $typeCode = $accountTypes[$type]['code'];
        }

        // Generate unique 8-digit suffix
        do {
            $number = $typeCode . mt_rand(10000000, 99999999);
        } while (self::where('account_number', $number)->exists());

        return $number;
    }

    /**
     * Relationships
     */
    /**
     * Deposits for this account
     */
    public function deposits(): HasMany
    {
        return $this->hasMany(Deposit::class);
    }

    /**
     * Withdrawals for this account
     */
    public function withdrawals(): HasMany
    {
        return $this->hasMany(Withdrawal::class);
    }


    public function cryptoBalances()
    {
        return $this->hasMany(AccountCryptoBalance::class);
    }

    public function cryptoBalance(string $code, string $network)
    {
        return $this->cryptoBalances()
            ->where('code', $code)
            ->where('network', $network)
            ->first();
    }

    public function cryptoFiatSwaps()
    {
        return $this->hasMany(CryptoFiatSwap::class);
    }


    // An account belongs to a profile
    public function profile()
    {
        return $this->belongsTo(Profile::class);
    }

    // An account can have multiple transactions
    public function transactions()
    {
        return $this->hasMany(Transaction::class);
    }

    public function transfers()
    {
        return $this->hasMany(Transfer::class);
    }

    public function loans()
    {
        return $this->hasMany(Loan::class);
    }
    /**
     * Wallet reserves associated with this account.
     */
    public function reserves(): HasMany
    {
        return $this->hasMany(WalletReserve::class);
    }

    /**
     * Get total pending reserve for this account.
     */
    public function getTotalPendingReserveAttribute(): string
    {
        return $this->relationLoaded('reserves')
            ? (string) $this->reserves->where('status', 'pending')->sum('amount')
            : (string) $this->reserves()->where('status', 'pending')->sum('amount');
    }


    /**
     * Calculate available balance (balance minus pending reserves)
     */
    public function getAvailableBalanceAttribute(): string
    {
        $reserved = $this->relationLoaded('reserves')
            ? (string) $this->reserves->where('status', 'pending')->sum('amount')
            : (string) $this->reserves()->where('status', 'pending')->sum('amount');

        return bcsub((string) $this->balance, $reserved, 2);
    }


    public function getDashboardBalancesAttribute(): array
    {
        $reserved = (string) $this->reserves()->where('status', 'pending')->sum('amount');

        return [
            'total' => (string) $this->balance,
            'reserved' => $reserved,
            'available' => bcsub((string) $this->balance, $reserved, 2),
        ];
    }

}
