<?php

namespace App\Trading\Risk;

use App\Enums\MarketType;
use App\Enums\WalletType;
use App\Models\Asset;
use App\Models\RiskSetting;
use App\Models\WalletBalance;
use App\Trading\Exposure\ExposureManagementEngine;
use Illuminate\Support\Facades\Log;

class RiskManagementEngine
{
    protected ExposureManagementEngine $exposureEngine;

    public function __construct(ExposureManagementEngine $exposureEngine)
    {
        $this->exposureEngine = $exposureEngine;
    }

    /**
     * Evaluate risk for a potential trade.
     */
    public function evaluateTradeRisk(
        WalletBalance $wallet,
        Asset $asset,
        MarketType $marketType,
        string $direction,
        string $amount
    ): array {
        $risks = [];
        $riskScore = 0;
        $canTrade = true;

        // Check exposure limits
        $exposureRisk = $this->checkExposureRisk(
            $asset,
            $marketType,
            $wallet->wallet_type,
            $direction,
            $amount
        );

        if (!$exposureRisk['passed']) {
            $risks[] = $exposureRisk['message'];
            $riskScore += 30;
            $canTrade = false;
        }

        // Check wallet balance risk
        $balanceRisk = $this->checkBalanceRisk($wallet, $amount);
        if (!$balanceRisk['passed']) {
            $risks[] = $balanceRisk['message'];
            $riskScore += 20;
            $canTrade = false;
        }

        // Check concentration risk
        $concentrationRisk = $this->checkConcentrationRisk($wallet, $amount);
        if (!$concentrationRisk['passed']) {
            $risks[] = $concentrationRisk['message'];
            $riskScore += 15;
        }

        // Check volatility risk (for real wallets)
        if ($wallet->wallet_type === WalletType::REAL) {
            $volatilityRisk = $this->checkVolatilityRisk($asset);
            if (!$volatilityRisk['passed']) {
                $risks[] = $volatilityRisk['message'];
                $riskScore += 10;
            }
        }

        return [
            'can_trade' => $canTrade,
            'risk_score' => $riskScore,
            'risk_level' => $this->getRiskLevel($riskScore),
            'risks' => $risks,
            'warnings' => $this->getWarnings($riskScore),
        ];
    }

    /**
     * Check exposure risk.
     */
    protected function checkExposureRisk(
        Asset $asset,
        MarketType $marketType,
        WalletType $walletType,
        string $direction,
        string $amount
    ): array {
        // Get max exposure settings
        $maxExposure = RiskSetting::get('max_exposure_per_asset', [
            'amount' => 100000,
            'percentage' => 20,
        ]);

        $maxDirectionPercentage = RiskSetting::get('max_exposure_per_direction', [
            'percentage' => 60,
        ])['percentage'];

        // Check if adding this trade would exceed limits
        $exceedsLimit = $this->exposureEngine->exceedsExposureLimit(
            $asset,
            $marketType,
            $walletType,
            $direction,
            $amount
        );

        if ($exceedsLimit) {
            return [
                'passed' => false,
                'message' => "Trade would exceed maximum exposure limit for {$direction} direction",
            ];
        }

        // Get current exposure
        $exposure = $this->exposureEngine->getAssetExposure($asset, $marketType, $walletType);
        $currentTotal = $exposure['total_exposure'];

        // Check total exposure limit
        if (bccomp($currentTotal, (string) $maxExposure['amount'], 8) > 0) {
            return [
                'passed' => false,
                'message' => 'Maximum asset exposure limit reached',
            ];
        }

        return ['passed' => true];
    }

    /**
     * Check balance risk.
     */
    protected function checkBalanceRisk(WalletBalance $wallet, string $amount): array
    {
        $availableBalance = $wallet->available_balance;

        // Check if amount exceeds available balance
        if (bccomp($amount, $availableBalance, 8) > 0) {
            return [
                'passed' => false,
                'message' => 'Insufficient balance',
            ];
        }

        // Check if trade is more than 50% of balance (warning)
        $halfBalance = bcdiv($availableBalance, '2', 8);
        if (bccomp($amount, $halfBalance, 8) > 0) {
            return [
                'passed' => true,
                'message' => 'Trade amount exceeds 50% of available balance',
                'warning' => true,
            ];
        }

        return ['passed' => true];
    }

    /**
     * Check concentration risk.
     */
    protected function checkConcentrationRisk(WalletBalance $wallet, string $amount): array
    {
        // Get total locked balance
        $totalLocked = $wallet->locked_balance;
        $newLocked = bcadd($totalLocked, $amount, 8);

        // Check if total locked would exceed 80% of balance
        $eightyPercent = bcmul($wallet->balance, '0.8', 8);

        if (bccomp($newLocked, $eightyPercent, 8) > 0) {
            return [
                'passed' => false,
                'message' => 'Too many active trades - would lock more than 80% of balance',
            ];
        }

        return ['passed' => true];
    }

    /**
     * Check volatility risk.
     */
    protected function checkVolatilityRisk(Asset $asset): array
    {
        // This would integrate with market data to check current volatility
        // For now, return passed
        return ['passed' => true];
    }

    /**
     * Get risk level from score.
     */
    protected function getRiskLevel(int $score): string
    {
        if ($score === 0) {
            return 'low';
        } elseif ($score < 30) {
            return 'medium';
        } elseif ($score < 50) {
            return 'high';
        } else {
            return 'critical';
        }
    }

    /**
     * Get warnings based on risk score.
     */
    protected function getWarnings(int $score): array
    {
        $warnings = [];

        if ($score >= 15 && $score < 30) {
            $warnings[] = 'Consider reducing trade size';
        }

        if ($score >= 30 && $score < 50) {
            $warnings[] = 'High risk trade - proceed with caution';
        }

        if ($score >= 50) {
            $warnings[] = 'Critical risk level - trade blocked';
        }

        return $warnings;
    }

    /**
     * Calculate recommended trade size.
     */
    public function getRecommendedTradeSize(WalletBalance $wallet): string
    {
        $availableBalance = $wallet->available_balance;

        // Recommend 5% of available balance
        $recommended = bcmul($availableBalance, '0.05', 8);

        // Minimum $1
        if (bccomp($recommended, '1', 8) < 0) {
            $recommended = '1';
        }

        return $recommended;
    }

    /**
     * Get risk settings.
     */
    public function getRiskSettings(): array
    {
        return [
            'max_exposure_per_asset' => RiskSetting::get('max_exposure_per_asset'),
            'max_exposure_per_direction' => RiskSetting::get('max_exposure_per_direction'),
            'exposure_rebalancing' => RiskSetting::get('exposure_rebalancing'),
            'payout_adjustment_range' => RiskSetting::get('payout_adjustment_range'),
            'volatility_thresholds' => RiskSetting::get('volatility_thresholds'),
        ];
    }

    /**
     * Update risk setting.
     */
    public function updateRiskSetting(string $key, array $value): bool
    {
        try {
            RiskSetting::set($key, $value);

            Log::info('Risk setting updated', [
                'key' => $key,
                'value' => $value,
            ]);

            return true;
        } catch (\Exception $e) {
            Log::error('Failed to update risk setting', [
                'key' => $key,
                'error' => $e->getMessage(),
            ]);

            return false;
        }
    }

    /**
     * Check if rebalancing is needed.
     */
    public function needsRebalancing(
        Asset $asset,
        MarketType $marketType,
        WalletType $walletType
    ): bool {
        $rebalancingSettings = RiskSetting::get('exposure_rebalancing', [
            'enabled' => true,
            'threshold' => 70,
        ]);

        if (!$rebalancingSettings['enabled']) {
            return false;
        }

        $exposure = $this->exposureEngine->getAssetExposure($asset, $marketType, $walletType);

        $upRatio = $exposure['up_exposure']['ratio'] * 100;
        $downRatio = $exposure['down_exposure']['ratio'] * 100;

        return $upRatio > $rebalancingSettings['threshold']
            || $downRatio > $rebalancingSettings['threshold'];
    }
}

// Made with Bob