<?php

namespace App\Models;

use App\Enums\MarketType;
use App\Enums\WalletType;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class PayoutRule extends Model
{
    use HasFactory;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'wallet_type',
        'market_type',
        'asset_id',
        'base_payout_percentage',
        'min_payout_percentage',
        'max_payout_percentage',
        'volatility_adjustment',
        'exposure_adjustment',
        'is_active',
        'priority',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'wallet_type' => WalletType::class,
        'market_type' => MarketType::class,
        'base_payout_percentage' => 'decimal:2',
        'min_payout_percentage' => 'decimal:2',
        'max_payout_percentage' => 'decimal:2',
        'volatility_adjustment' => 'boolean',
        'exposure_adjustment' => 'boolean',
        'is_active' => 'boolean',
        'priority' => 'integer',
    ];

    /**
     * Get the asset if specified.
     */
    public function asset(): BelongsTo
    {
        return $this->belongsTo(Asset::class);
    }

    /**
     * Calculate adjusted payout percentage.
     */
    public function calculatePayout(
        float $volatility = 0.0,
        float $exposureRatio = 0.0
    ): float {
        $payout = (float) $this->base_payout_percentage;

        // Apply volatility adjustment
        if ($this->volatility_adjustment) {
            $payout = $this->applyVolatilityAdjustment($payout, $volatility);
        }

        // Apply exposure adjustment
        if ($this->exposure_adjustment) {
            $payout = $this->applyExposureAdjustment($payout, $exposureRatio);
        }

        // Ensure within bounds
        $payout = max($payout, (float) $this->min_payout_percentage);
        $payout = min($payout, (float) $this->max_payout_percentage);

        return round($payout, 2);
    }

    /**
     * Apply volatility adjustment to payout.
     */
    protected function applyVolatilityAdjustment(float $payout, float $volatility): float
    {
        // Higher volatility = lower payout (risk management)
        // Volatility ranges: 0-1 (low), 1-2 (medium), 2+ (high)
        
        if ($volatility < 1.0) {
            // Low volatility: slight increase
            return $payout + 1.0;
        } elseif ($volatility < 2.0) {
            // Medium volatility: no change
            return $payout;
        } else {
            // High volatility: decrease
            $adjustment = min(($volatility - 2.0) * 2, 5.0);
            return $payout - $adjustment;
        }
    }

    /**
     * Apply exposure adjustment to payout.
     */
    protected function applyExposureAdjustment(float $payout, float $exposureRatio): float
    {
        // Higher exposure in one direction = lower payout for that direction
        // Exposure ratio: 0-1 (balanced to heavily skewed)
        
        if ($exposureRatio < 0.6) {
            // Balanced exposure: no change
            return $payout;
        } elseif ($exposureRatio < 0.75) {
            // Moderate imbalance: slight decrease
            return $payout - 2.0;
        } else {
            // Heavy imbalance: significant decrease
            $adjustment = min(($exposureRatio - 0.75) * 20, 5.0);
            return $payout - $adjustment;
        }
    }

    /**
     * Scope to filter by wallet type.
     */
    public function scopeForWalletType($query, WalletType $type)
    {
        return $query->where('wallet_type', $type);
    }

    /**
     * Scope to filter by market type.
     */
    public function scopeForMarketType($query, MarketType $type)
    {
        return $query->where('market_type', $type);
    }

    /**
     * Scope to filter by asset.
     */
    public function scopeForAsset($query, ?int $assetId)
    {
        if ($assetId === null) {
            return $query->whereNull('asset_id');
        }
        
        return $query->where(function ($q) use ($assetId) {
            $q->where('asset_id', $assetId)
              ->orWhereNull('asset_id');
        });
    }

    /**
     * Scope to filter active rules.
     */
    public function scopeActive($query)
    {
        return $query->where('is_active', true);
    }

    /**
     * Scope to order by priority.
     */
    public function scopeByPriority($query)
    {
        return $query->orderBy('priority', 'desc');
    }
}

// Made with Bob