<?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\Support\Str;

class Transaction extends Model
{
    use HasFactory;
    use VisibleToAdmin;

    // This tells the trait how to reach the user who controls visibility
    protected function adminVisibilityRelation(): string
    {
        return 'account.profile.user';
    }

    // Status constants
    const STATUS_PENDING = 'pending';
    const STATUS_COMPLETED = 'completed';
    const STATUS_APPROVED = 'approved';
    const STATUS_FAILED = 'failed';
    const STATUS_REJECTED = 'rejected';

    // Types
    public const OUTGOING_TYPES = [
        'withdrawal',
        'transfer_out',
        'trade',
        'swap_debit',
    ];

    public const INCOMING_TYPES = [
        'deposit',
        'transfer_in',
        'swap_credit',
        'referral_bonus',
        'signup_bonus',
        'loan',
    ];

    protected $fillable = [
        'account_id',
        'deposit_id',
        'withdrawal_id',
        'transfer_id',
        'loan_id',
        'referral_user_id',
        'crypto_balance_id',
        'idempotency_key',
        'type',
        'method',
        'amount',
        'balance_after',
        'description',
        'transaction_ref',
        'status',
        'created_at',
        'updated_at',
    ];

    protected $casts = [
        'amount' => 'decimal:2',
        'balance_after' => 'decimal:2',
    ];

    protected $attributes = [
        'status' => self::STATUS_PENDING,
    ];

    /*------------------------------------
     | RELATIONS
     ------------------------------------*/
    public function account()
    {
        return $this->belongsTo(Account::class);
    }

    public function deposit()
    {
        return $this->belongsTo(Deposit::class, 'deposit_id');
    }

    public function withdrawal()
    {
        return $this->belongsTo(Withdrawal::class, 'withdrawal_id');
    }

    public function transfer()
    {
        return $this->belongsTo(Transfer::class, 'transfer_id');
    }


    public function loan()
    {
        return $this->belongsTo(Loan::class, 'loan_id');
    }

    public function cryptoBalance()
    {
        return $this->belongsTo(AccountCryptoBalance::class, 'crypto_balance_id');
    }

    public function cryptoFiatSwap()
    {
        return $this->belongsTo(CryptoFiatSwap::class, 'crypto_balance_id', 'crypto_balance_id');
    }
    /*------------------------------------
     | BOOT
     ------------------------------------*/
    protected $cascadeDeletes = [
        'deposit',
        'withdrawal',
        'transfer',
        'loan',
        'cryptoFiatSwap',
    ];
    protected static function booted()
    {
        static::creating(function ($transaction) {
            if (empty($transaction->transaction_ref)) {
                $transaction->transaction_ref = self::generateRef();
            }
        });

        static::deleting(function ($transaction) {
            foreach ($transaction->cascadeDeletes as $relationName) {
                try {
                    $relation = $transaction->$relationName();

                    if ($relation instanceof \Illuminate\Database\Eloquent\Relations\Relation) {
                        if ($relation instanceof \Illuminate\Database\Eloquent\Relations\BelongsToMany) {
                            $relation->detach();
                        } else {
                            $relation->get()->each(fn($item) => $item->delete());
                        }
                    }
                } catch (\Throwable $e) {
                    // Ignore if relation doesn't exist or fails
                    continue;
                }
            }
        });
    }

    protected static function generateRef(): string
    {
        do {
            $ref = 'TXN-' . strtoupper(Str::random(10));
        } while (self::where('transaction_ref', $ref)->exists());

        return $ref;
    }

    /*------------------------------------
     | SCOPES
     ------------------------------------*/
    public function scopeIncoming($query)
    {
        return $query->whereIn('type', self::INCOMING_TYPES);
    }

    public function scopeOutgoing($query)
    {
        return $query->whereIn('type', self::OUTGOING_TYPES);
    }

    /*------------------------------------
     | HELPERS
     ------------------------------------*/

    public function customerName(): string
    {
        return $this->account->profile->user->name
            ?? 'Valued Customer';
    }


    // Safe user
    public function user()
    {
        return $this->account?->profile?->user;
    }

    public function userUrl(): ?string
    {
        return $this->user() ? route('admin.users.show', $this->user()) : null;
    }

    public function maskedAccount(): string
    {
        return $this->account?->masked_account_number ?? 'XXXX-XXXX';
    }

    /**
     * Get the transaction currency code or symbol
     */
    public function transactionCurrency(): string
    {
        // Crypto transaction → return code like BTC, ETH
        if ($this->crypto_balance_id) {
            return $this->cryptoBalance?->symbol ?? 'CRYPTO';
        }

        // Fiat transaction → profile currency first, fallback to USD
        return $this->account?->profile?->currency
            ?? 'USD';
    }

    /**
     * Get the currency symbol for display
     */
    public function currencySymbol(): string
    {
        $currency = $this->transactionCurrency();

        // Only convert to symbol for fiat currencies
        if (!$this->crypto_balance_id) {
            return Currency::symbol($currency);
        }

        // For crypto, just return code (BTC, ETH)
        return $currency;
    }

    /**
     * Format the transaction amount for display
     */
    /**
     * Format the transaction amount for display
     */
    public function formattedAmount(
        bool $withSign = true,
        bool $withCurrency = true,
        bool $useSymbol = true
    ): string {
        $amount = $this->amount ?? 0;

        // Crypto transaction → 8 decimals
        if ($this->crypto_balance_id) {
            $amountStr = number_format($amount, 8, '.', '');
            $amountStr = rtrim(rtrim($amountStr, '0'), '.');

            if ($withSign) {
                $sign = match ($this->type) {
                    'deposit', 'transfer_in', 'referral_bonus', 'signup_bonus' => '+',
                    'withdrawal', 'transfer_out', 'trade', 'swap_debit' => '-',
                    default => '',
                };
                $amountStr = $sign . ' ' . $amountStr;
            }

            if ($withCurrency) {
                $amountStr .= ' ' . $this->transactionCurrency(); // BTC, ETH, etc.
            }

            return $amountStr;
        }

        // Fiat transaction → use profile currency
        $currencyCode = $this->transactionCurrency();
        $decimals = Currency::decimals($currencyCode);
        $symbol = $useSymbol ? Currency::symbol($currencyCode) : $currencyCode;

        $formatted = number_format((float) $amount, $decimals, '.', ',');

        if ($withSign) {
            $sign = match ($this->type) {
                'deposit', 'transfer_in', 'referral_bonus', 'signup_bonus' => '+',
                'withdrawal', 'transfer_out', 'trade', 'swap_debit' => '-',
                default => '',
            };
            $formatted = $sign . ' ' . $formatted;
        }

        if ($withCurrency) {
            $formatted = $symbol . $formatted;
        }

        return $formatted;
    }


    public function statusLabel(): string
    {
        return match ($this->status) {
            'approved' => 'completed',
            'pending' => 'initiated',
            'rejected' => 'declined',
            default => 'processed',
        };
    }

    public function typeLabel(): string
    {
        return match ($this->type) {
            'deposit' => 'Deposit',
            'loan' => 'Loan',
            'grant' => 'Grant',
            'refund' => 'Refund',
            'withdrawal' => 'Withdrawal',
            'investment' => 'Investment',
            'profit' => 'Profit',
            default => 'Transaction',
        };
    }

    public function statusGradient(): string
    {
        return match ($this->status ?? 'pending') {
            'approved' => 'linear-gradient(90deg, #22c55e, #16a34a)',
            'pending' => 'linear-gradient(90deg, #facc15, #f59e0b)',
            'rejected' => 'linear-gradient(90deg, #ef4444, #b91c1c)',
            default => 'linear-gradient(90deg, #9ca3af, #6b7280)',
        };
    }

    public function title(): string
    {
        return $this->typeLabel();
    }

    public function generateMessage(): string
    {
        $transactionAmount = $this->formattedAmount(withSign: true, withCurrency: true);
        $availableBalance = Currency::format(
            $this->account?->available_balance ?? 0,
            $this->transactionCurrency()
        );

        return "{$this->title()} of {$transactionAmount} has been {$this->statusLabel()} for account {$this->maskedAccount()}. Ref: {$this->transaction_ref}. Available balance: {$availableBalance}.";
    }


    /*------------------------------------
     | ATTRIBUTE HELPERS
     ------------------------------------*/
    public function getAdminUrlAttribute(): ?string
    {
        return match ($this->type) {
            'deposit' => $this->deposit ? route('admin.deposit.show', $this->deposit) : null,
            'withdrawal' => $this->withdrawal ? route('admin.withdrawal.show', $this->withdrawal) : null,
            'loan' => $this->loan ? route('admin.loans.show', $this->loan) : null,
            'transfer_in', 'transfer_out' => $this->transfer ? route('admin.transfer.show', $this->transfer) : null,
            default => route('admin.dashboard', $this),
        };
    }


    public function getFormattedAmountAttribute(): string
    {
        return $this->formattedAmount();
    }

    public function getBadgeClassesAttribute(): array
    {
        return match ($this->status) {
            'approved', 'completed' => ([
                'bg' => 'bg-green-100 text-green-800 dark:bg-green-800/20 dark:text-green-300',
                'icon' => 'bg-green-500',
            ]),
            'pending', 'review' => ([
                'bg' => 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/20 dark:text-yellow-300',
                'icon' => 'bg-yellow-600',
            ]),
            'failed', 'rejected' => ([
                'bg' => 'bg-red-100 text-red-800 dark:bg-red-800/20 dark:text-red-300',
                'icon' => 'bg-red-500',
            ]),
            default => ([
                'bg' => 'bg-gray-100 text-gray-600 dark:bg-gray-700/20 dark:text-gray-300',
                'icon' => 'bg-gray-400',
            ]),
        };
    }

    /**
     * Get the user URL (admin view)
     */
    public function getUserUrlAttribute(): ?string
    {
        $user = $this->account?->profile?->user;
        return $user ? route('admin.users.show', $user) : null;
    }
}
