<?php

namespace App\Models;

use App\Enums\TransactionCalcType;
use App\Enums\TransactionStatus;
use App\Enums\TransactionType;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphTo;

class Transaction extends Model
{
    use HasFactory;

    /**
     * Transaction Types
     */


    /**
     * Transaction Categories
     */
    const CATEGORY_CREDIT = 'credit';
    const CATEGORY_DEBIT = 'debit';

    /**
     * Transaction Statuses
     */
    const STATUS_PENDING = 'pending';
    const STATUS_PROCESSING = 'processing';
    const STATUS_COMPLETED = 'completed';
    const STATUS_FAILED = 'failed';
    const STATUS_CANCELLED = 'cancelled';
    const STATUS_REVERSED = 'reversed';

    protected $fillable = [
        'transaction_id',
        'user_id',
        'type',
        'category',
        'method',
        'amount',
        'balance_before',
        'balance_after',
        'description',
        'metadata',
        'payment_proof',
        'status',
        'reference_type',
        'reference_id',
        'created_date',
        'processed_at',
    ];

    protected $casts = [
        'amount' => 'decimal:2',
        'balance_before' => 'decimal:2',
        'balance_after' => 'decimal:2',
        'metadata' => 'array',
        'created_date' => 'datetime',
        'processed_at' => 'datetime',
    ];

    /**
     * Generate unique transaction ID on creation
     */
    protected static function boot()
    {
        parent::boot();

        static::creating(function ($model) {
            if (empty($model->transaction_id)) {
                $model->transaction_id = static::generateTransactionId($model->type);
            }

            // Set created_date if not set
            if (empty($model->created_date)) {
                $model->created_date = now();
            }
        });
    }

    /**
     * Generate transaction ID based on type
     */
    public static function generateTransactionId($type)
    {
        $prefix = match ($type) {
            TransactionType::DEPOSIT->value => 'DEP',
            TransactionType::WITHDRAWAL->value => 'WD',
            TransactionType::TRANSFER->value => 'TRF',
            TransactionType::BONUS->value => 'BNS',
            TransactionType::COMMISSION->value => 'COM',
            TransactionType::INVESTMENT->value => 'INV',
            TransactionType::PROFIT->value => 'PRF',
            TransactionType::REFUND->value => 'REF',
            TransactionType::FEE->value => 'FEE',
            default => 'TXN',
        };

        return $prefix . '-' . strtoupper(uniqid());
    }

    /*
    |--------------------------------------------------------------------------
    | Relationships
    |--------------------------------------------------------------------------
    */

    /**
     * Get the user who owns the transaction
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }
    
    public function paymentMethod(): BelongsTo
    {
        return $this->belongsTo(PaymentMethod::class, 'method');
    }

    public function withdrawalMethod(): BelongsTo
    {
        return $this->belongsTo(WithdrawalMethod::class, 'method');
    }
    /**
     * Get the related model (polymorphic)
     * Can be: Order, Deposit, Withdrawal, UserPlan, etc.
     */
    public function reference(): MorphTo
    {
        return $this->morphTo();
    }

    /*
    |--------------------------------------------------------------------------
    | Scopes
    |--------------------------------------------------------------------------
    */

    /**
     * Scope: Completed transactions
     */
    public function scopeCompleted($query)
    {
        return $query->where('status', TransactionStatus::COMPLETED->value);
    }

    /**
     * Scope: Pending transactions
     */
    public function scopePending($query)
    {
        return $query->where('status', TransactionStatus::PENDING->value);
    }

    /**
     * Scope: Failed transactions
     */
    public function scopeFailed($query)
    {
        return $query->where('status', TransactionStatus::FAILED->value);
    }

    /**
     * Scope: By type
     */
    public function scopeByType($query, $type)
    {
        return $query->where('type', $type);
    }

    /**
     * Scope: Deposits
     */
    public function scopeDeposits($query)
    {
        return $query->where('type', TransactionType::DEPOSIT->value);
    }

    /**
     * Scope: Deposits
     */
    public function scopeRoi($query)
    {
        return $query->where('type', TransactionType::ROI->value);
    }

    /**
     * Scope: Withdrawals
     */
    public function scopeWithdrawals($query)
    {
        return $query->where('type', TransactionType::WITHDRAWAL->value);
    }

    /**
     * Scope: Credits (money in)
     */
    public function scopeCredits($query)
    {
        return $query->where('category', TransactionCalcType::CREDIT->value);
    }

    /**
     * Scope: Debits (money out)
     */
    public function scopeDebits($query)
    {
        return $query->where('category', TransactionCalcType::DEBIT->value);
    }

    /**
     * Scope: By date range
     */
    public function scopeDateRange($query, $startDate, $endDate)
    {
        return $query->whereBetween('created_date', [$startDate, $endDate]);
    }

    /**
     * Scope: Today's transactions
     */
    public function scopeToday($query)
    {
        return $query->whereDate('created_date', today());
    }

    /**
     * Scope: This month's transactions
     */
    public function scopeThisMonth($query)
    {
        return $query->whereMonth('created_date', now()->month)
            ->whereYear('created_date', now()->year);
    }

    /*
    |--------------------------------------------------------------------------
    | Helper Methods
    |--------------------------------------------------------------------------
    */

    /**
     * Check if transaction is completed
     */
    public function isCompleted(): bool
    {
        return $this->status === TransactionStatus::COMPLETED->value;
    }

    /**
     * Check if transaction is pending
     */
    public function isPending(): bool
    {
        return $this->status === TransactionStatus::PENDING->value;
    }

    /**
     * Check if transaction is failed
     */
    public function isFailed(): bool
    {
        return $this->status === TransactionStatus::FAILED->value;
    }

    /**
     * Check if transaction is credit
     */
    public function isCredit(): bool
    {
        return $this->category === TransactionCalcType::CREDIT->value;
    }

    /**
     * Check if transaction is debit
     */
    public function isDebit(): bool
    {
        return $this->category === TransactionCalcType::DEBIT->value;
    }

    /**
     * Mark transaction as completed
     */
    public function markAsCompleted()
    {
        $this->update([
            'status' => TransactionStatus::COMPLETED->value,
            'processed_at' => now(),
        ]);
    }

    /**
     * Mark transaction as failed
     */
    public function markAsFailed($reason = null)
    {
        $metadata = $this->metadata ?? [];
        $metadata['failure_reason'] = $reason;

        $this->update([
            'status' => TransactionStatus::FAILED->value,
            'metadata' => $metadata,
            'processed_at' => now(),
        ]);
    }

    /**
     * Reverse transaction
     */
    public function reverse($reason = null)
    {
        if (!$this->isCompleted()) {
            return false;
        }

        $metadata = $this->metadata ?? [];
        $metadata['reversal_reason'] = $reason;
        $metadata['reversed_at'] = now()->toDateTimeString();

        $this->update([
            'status' => TransactionStatus::REVERSED->value,
            'metadata' => $metadata,
        ]);

        // Create reversal transaction
        return static::create([
            'user_id' => $this->user_id,
            'type' => TransactionType::REFUND,
            'category' => $this->category === TransactionCalcType::CREDIT ? TransactionCalcType::DEBIT : TransactionCalcType::CREDIT,
            'method' => $this->method,
            'amount' => $this->amount,
            'description' => "Reversal of transaction {$this->transaction_id}. Reason: {$reason}",
            'reference_type' => get_class($this),
            'reference_id' => $this->id,
            'status' => TransactionStatus::COMPLETED,
            'processed_at' => now(),
        ]);
    }

    /**
     * Get formatted amount with sign
     */
    public function getFormattedAmountAttribute(): string
    {
        $sign = $this->isCredit() ? '+' : '-';
        return $sign . number_format($this->amount, 2);
    }

    /**
     * Get transaction type label
     */
    public function getTypeLabelAttribute(): string
    {
        return ucfirst(str_replace('_', ' ', $this->type));
    }

    /**
     * Get status label with color
     */
    public function getStatusBadgeAttribute(): array
    {
        return match ($this->status) {
            TransactionStatus::COMPLETED->value => ['label' => 'Completed', 'color' => 'green'],
            TransactionStatus::PENDING->value => ['label' => 'Pending', 'color' => 'yellow'],
            TransactionStatus::PROCESSING->value => ['label' => 'Processing', 'color' => 'blue'],
            TransactionStatus::FAILED->value => ['label' => 'Failed', 'color' => 'red'],
            TransactionStatus::CANCELLED->value => ['label' => 'Cancelled', 'color' => 'gray'],
            TransactionStatus::REVERSED->value => ['label' => 'Reversed', 'color' => 'orange'],
            default => ['label' => 'Unknown', 'color' => 'gray'],
        };
    }

    /*
    |--------------------------------------------------------------------------
    | Static Methods
    |--------------------------------------------------------------------------
    */

    /**
     * Create a deposit transaction
     */
    public static function createDeposit($userId, $amount, $method, $account="main", $description = null)
    {

        $config = [
            "account" => $account,
            "system_currency" => system_settings('currency'),
            "method_currency" => $method->symbol,
            "exhange_rate" => 1,
            "system_exchange_rate" => 1,
            
        ];
        return static::create([
            'user_id' => $userId,
            'type' => TransactionType::DEPOSIT->value,
            'category' => TransactionCalcType::CREDIT->value,
            'method' => $method->id,
            'amount' => $amount,
            'description' => $description ?? "Deposit via {$method->name}",
            'payment_proof' => '',
            'metadata' => $config,
            'status' => TransactionStatus::PENDING->value,
        ]);
    }

    public static function createInvestment($userId, $amount, $plan, $description = null)
    {

        $config = [
            "account" => "main",
            "system_currency" => system_settings('currency'),
            "exhange_rate" => 1,
        ];
        return static::create([
            'user_id' => $userId,
            'type' => TransactionType::INVESTMENT->value,
            'category' => TransactionCalcType::DEBIT->value,
            'method' => $plan->id,
            'amount' => $amount,
            'description' => $description ?? "Investing via {$plan->name}",
            'payment_proof' => '',
            'metadata' => $config,
            'status' => TransactionStatus::COMPLETED->value,
        ]);
    }

    public static function createMarket($userId, $amount, $market, $description = null)
    {

        $config = [
            "account" => "main",
            "system_currency" => system_settings('currency'),
            "exhange_rate" => 1,
        ];
        return static::create([
            'user_id' => $userId,
            'type' => TransactionType::MARKET->value,
            'category' => TransactionCalcType::DEBIT->value,
            'method' => $market->id,
            'amount' => $amount,
            'description' => $description ?? "Purchased {$market->name}",
            'payment_proof' => '',
            'metadata' => $config,
            'status' => TransactionStatus::COMPLETED->value,
        ]);
    }

    /**
     * Create a withdrawal transaction
     */
    public static function createWithdrawal($userId, $amount, $method, $details, $description = null)
    {

        $config = [
            "account" => "main",
            "system_currency" => system_settings('currency'),
            "method_currency" => $method->symbol,
            "exhange_rate" => 1,
            "system_exchange_rate" => 1,
            "details" => $details ?? []
        ];
        return static::create([
            'user_id' => $userId,
            'type' => TransactionType::WITHDRAWAL->value,
            'category' => TransactionCalcType::DEBIT->value,
            'method' => $method->id,
            'amount' => $amount,
            'description' => $description ?? "Withdrawal via {$method->name}",
            'metadata' => $config,
            'status' => TransactionStatus::PENDING->value,
        ]);
    }

    /**
     * Create a bonus transaction
     */
    public static function createBonus($userId, $amount, $description = null)
    {
        $user = User::find($userId);
        $balance = $user->balance;

        return static::create([
            'user_id' => $userId,
            'type' => TransactionType::BONUS->value,
            'category' => TransactionCalcType::CREDIT->value,
            'amount' => $amount,
            'balance_before' => $balance->bonus,
            'balance_after' => $balance->bonus + $amount,
            'description' => $description ?? "Bonus credit",
            'status' => TransactionStatus::COMPLETED->value,
            'processed_at' => now(),
        ]);
    }

    /**
     * Create a profit transaction
     */
    public static function createProfit($userId, $amount, $description = null, $referenceModel = null)
    {
        $user = User::find($userId);
        $balance = $user->balance;

        return static::create([
            'user_id' => $userId,
            'type' => TransactionType::PROFIT->value,
            'category' => TransactionCalcType::CREDIT->value,
            'amount' => $amount,
            'balance_before' => $balance->profit,
            'balance_after' => $balance->profit + $amount,
            'description' => $description ?? "Trading profit",
            'reference_type' => $referenceModel ? get_class($referenceModel) : null,
            'reference_id' => $referenceModel ? $referenceModel->id : null,
            'status' => TransactionStatus::COMPLETED->value,
            'processed_at' => now(),
        ]);
    }
    
    public static function createROI($userId, $amount,$userPlan, $description = null, $referenceModel = null)
    {
        $user = User::find($userId);
        $balance = $user->balance;
$config = [];
        return static::create([
            'user_id' => $userId,
            'type' => TransactionType::ROI->value,
            'category' => TransactionCalcType::CREDIT->value,
            'method' => $userPlan->id,
            'amount' => $amount,
            'description' => $description ?? "Return on investment ",
            'metadata' => $config,
            'status' => TransactionStatus::PENDING->value,
        ]);
    }

    /**
     * Get user's transaction summary
     */
    public static function getUserSummary($userId)
    {
        return [
            'total_deposits' => static::where('user_id', $userId)
                ->where('type', TransactionType::DEPOSIT->value)
                ->where('status', TransactionStatus::COMPLETED->value)
                ->sum('amount'),

            'total_withdrawals' => static::where('user_id', $userId)
                ->where('type', TransactionType::WITHDRAWAL->value)
                ->where('status', TransactionStatus::COMPLETED->value)
                ->sum('amount'),

            'total_profit' => static::where('user_id', $userId)
                ->where('type', TransactionType::PROFIT->value)
                ->where('status', TransactionStatus::COMPLETED->value)
                ->sum('amount'),

            'total_bonus' => static::where('user_id', $userId)
                ->where('type', TransactionType::BONUS->value)
                ->where('status', TransactionStatus::COMPLETED->value)
                ->sum('amount'),

            'pending_deposits' => static::where('user_id', $userId)
                ->where('type', TransactionType::DEPOSIT->value)
                ->where('status', TransactionStatus::PENDING->value)
                ->count(),

            'pending_withdrawals' => static::where('user_id', $userId)
                ->where('type', TransactionType::WITHDRAWAL->value)
                ->where('status', TransactionStatus::PENDING->value)
                ->count(),
        ];
    }
    
    public function withdrawalDetails(){
        return data_get($this->metadata , 'details');
    }
}