<?php

class InstitutionalDecisionEngine
{
    public static function synchronizeDualScenario(array $buyScenario, array $sellScenario, array $context = []): array
    {
        $contextBias = strtoupper((string)($context['context_bias'] ?? $context['htf_bias'] ?? 'WAIT'));
        $executionBias = strtoupper((string)($context['execution_bias'] ?? $context['ltf_bias'] ?? 'WAIT'));

        $directionalConflict = in_array($contextBias, ['BUY', 'SELL'], true)
            && in_array($executionBias, ['BUY', 'SELL'], true)
            && $contextBias !== $executionBias;

        $buy = self::normalizeScenario($buyScenario, 'BUY', $context);
        $sell = self::normalizeScenario($sellScenario, 'SELL', $context);

        if (!($confirmationStage === 'EXECUTION_CONFIRMED' || $confirmationCount >= 4)) {
            if ($confirmationCount >= 2) {
                $score = min($score, 6.8);
            } elseif ($confirmationCount >= 1) {
                $score = min($score, 5.5);
            } else {
                $score = min($score, 4.5);
            }
        }

        if ($directionalConflict) {
            $primary = $contextBias === 'SELL' ? $sell : $buy;
            $secondary = $primary['side'] === 'SELL' ? $buy : $sell;

            $primary['status'] = 'Directional Conflict - Wait';
            $primary['tone'] = 'amber';
            $primary['tradeable'] = false;
            $primary['instruction'] = 'Higher-timeframe and execution-timeframe bias conflict. Do not execute until alignment returns.';
        } else {
            $buyRank = $buy['institutional_score'] + ($contextBias === 'BUY' ? 8 : ($contextBias === 'SELL' ? -8 : 0));
            $sellRank = $sell['institutional_score'] + ($contextBias === 'SELL' ? 8 : ($contextBias === 'BUY' ? -8 : 0));
            $primary = $sellRank > $buyRank ? $sell : $buy;
            $secondary = $primary['side'] === 'SELL' ? $buy : $sell;

            if (abs($sell['institutional_score'] - $buy['institutional_score']) <= 3) {
                if ($contextBias === 'BUY') {
                    $primary = $buy; $secondary = $sell;
                } elseif ($contextBias === 'SELL') {
                    $primary = $sell; $secondary = $buy;
                }
            }
        }

        $decision = self::buildDecision($primary, $secondary, $context, $directionalConflict);

        return [
            'primary' => $primary,
            'secondary' => $secondary,
            'buy' => $buy,
            'sell' => $sell,
            'decision' => $decision,
            'directional_conflict' => $directionalConflict,
            'summary' => $directionalConflict
                ? 'Directional conflict: HTF ' . $contextBias . ', LTF ' . $executionBias . '. Wait for alignment.'
                : 'Primary scenario: ' . $primary['side'] . ' - ' . $primary['status'] . '. Secondary scenario: ' . $secondary['side'] . ' - ' . $secondary['status'] . '.',
        ];
    }

    public static function normalizeScenario(array $scenario, string $fallbackSide, array $context = []): array
    {
        $side = strtoupper((string)($scenario['side'] ?? $fallbackSide));
        $rawScore = self::num($scenario['score'] ?? $scenario['institutional_score'] ?? 0);
        $base100 = $rawScore <= 15 ? ($rawScore / 15) * 100 : $rawScore;
        $base100 = max(0, min(100, $base100));

        $adjusted = $base100;
        $reasons = is_array($scenario['reasons'] ?? null) ? $scenario['reasons'] : [];
        $warnings = [];

        $contextBias = strtoupper((string)($context['context_bias'] ?? $context['htf_bias'] ?? 'NEUTRAL'));
        $executionBias = strtoupper((string)($context['execution_bias'] ?? $context['ltf_bias'] ?? 'WAIT'));
        $confirmationStage = strtoupper((string)($context['confirmation_stage'] ?? 'CONFIRMATION_PENDING'));
        $confirmationCount = (int)($context['confirmation_count'] ?? 0);
        $partialCount = (int)($context['partial_confirmation_count'] ?? 0);
        $newsRisk = strtoupper((string)($context['news_risk'] ?? 'LOW'));
        $geoRisk = strtoupper((string)($context['geo_risk'] ?? 'LOW'));

        if ($contextBias === $side) {
            $adjusted += 8;
            $reasons[] = 'HTF context supports ' . $side . '.';
        } elseif (in_array($contextBias, ['BUY','SELL'], true)) {
            $adjusted -= 18;
            $warnings[] = 'HTF context conflicts with this scenario.';
        }

        if ($executionBias === $side) {
            $adjusted += 5;
            $reasons[] = 'Execution timeframe supports ' . $side . '.';
        } elseif (in_array($executionBias, ['BUY','SELL'], true)) {
            $adjusted -= 10;
            $warnings[] = 'Execution timeframe conflicts with this scenario.';
        }

        if (!empty($scenario['zone'])) {
            $adjusted += 5;
        } else {
            $adjusted -= 15;
            $warnings[] = 'No qualified institutional zone is available.';
        }

        if (!empty($scenario['fresh_entry_valid'])) {
            $adjusted += 4;
        } else {
            $adjusted -= 8;
            $warnings[] = 'Entry is late, tapped, or not fresh.';
        }

        if ($confirmationStage === 'EXECUTION_CONFIRMED' || $confirmationCount >= 4) {
            $adjusted += 8;
        } elseif ($confirmationCount >= 2) {
            $adjusted -= 6;
        } elseif ($confirmationCount >= 1 || $partialCount > 0) {
            $adjusted -= 12;
        } else {
            $adjusted -= 18;
        }

        if (in_array($newsRisk, ['HIGH','CRITICAL','EXTREME'], true)) $adjusted -= 8;
        elseif ($newsRisk === 'MEDIUM') $adjusted -= 3;

        if (in_array($geoRisk, ['HIGH','CRITICAL','EXTREME'], true)) $adjusted -= 6;
        elseif ($geoRisk === 'MEDIUM') $adjusted -= 2;

        $adjusted = max(0, min(100, $adjusted));

        /*
        |--------------------------------------------------------------------------
        | Execution-readiness cap
        |--------------------------------------------------------------------------
        | A scenario must not print 9/10 or 10/10 when confirmation is incomplete.
        |--------------------------------------------------------------------------
        */
        if (!($confirmationStage === 'EXECUTION_CONFIRMED' || $confirmationCount >= 4)) {
            if ($confirmationCount >= 2) {
                $adjusted = min($adjusted, 68);
            } elseif ($confirmationCount >= 1 || $partialCount > 0) {
                $adjusted = min($adjusted, 55);
            } else {
                $adjusted = min($adjusted, 45);
            }
        }

        $score10 = round($adjusted / 10, 1);

        $scenario['side'] = $side;
        $scenario['status'] = trim((string)($scenario['status'] ?? 'Watchlist'));
        $scenario['raw_score'] = round($base100, 1);
        $scenario['institutional_score'] = round($adjusted, 1);
        $scenario['score_10'] = $score10;
        $scenario['grade'] = self::grade($score10);
        $scenario['confidence'] = self::confidence($score10, $confirmationStage);
        $scenario['readiness'] = self::readiness($score10, $confirmationStage, $confirmationCount, $partialCount);
        $scenario['tradeable'] = self::isTradeable($scenario, $context);
        $scenario['reasons'] = array_values(array_unique(array_slice($reasons, 0, 8)));
        $scenario['warnings'] = array_values(array_unique(array_slice($warnings, 0, 8)));

        return $scenario;
    }

    private static function buildDecision(array $primary, array $secondary, array $context, bool $directionalConflict = false): array
    {
        $confirmationStage = strtoupper((string)($context['confirmation_stage'] ?? 'CONFIRMATION_PENDING'));
        $confirmationCount = (int)($context['confirmation_count'] ?? 0);
        $newsRisk = strtoupper((string)($context['news_risk'] ?? 'LOW'));
        $geoRisk = strtoupper((string)($context['geo_risk'] ?? 'LOW'));
        $contextBias = strtoupper((string)($context['context_bias'] ?? $context['htf_bias'] ?? 'WAIT'));
        $executionBias = strtoupper((string)($context['execution_bias'] ?? $context['ltf_bias'] ?? 'WAIT'));
        $score = (float)($primary['score_10'] ?? 0);
        $side = strtoupper((string)($primary['side'] ?? 'WAIT'));

        if ($directionalConflict) {
            $score = min($score, 4.5);
            return [
                'action' => 'WAIT',
                'label' => 'WAIT FOR ALIGNMENT',
                'tone' => 'amber',
                'execution_mode' => 'DIRECTIONAL_CONFLICT',
                'score_10' => $score,
                'score_100' => round($score * 10, 1),
                'raw_score_100' => $primary['raw_score'] ?? round($score * 10, 1),
                'confidence' => 'LOW',
                'grade' => 'C',
                'readiness' => 'Directional Conflict',
                'summary' => 'HTF bias is ' . $contextBias . ' while execution timeframe is ' . $executionBias . '. Wait for alignment.',
                'primary_side' => 'WAIT',
                'scenario_side' => $side,
                'secondary_side' => $secondary['side'] ?? '',
                'confirmation_stage' => $confirmationStage,
                'hard_block' => true,
                'directional_conflict' => true,
            ];
        }

        $confirmed = ($confirmationStage === 'EXECUTION_CONFIRMED' || $confirmationCount >= 4);

        if (!in_array($side, ['BUY','SELL'], true)) {
            $label = 'WAIT FOR STRUCTURE'; $action = 'WAIT'; $readiness = 'Wait'; $mode = 'WAIT';
            $score = min($score, 4.0);
        } elseif ($score < 5.5) {
            $label = $side . ' WATCHLIST'; $action = 'WAIT'; $readiness = 'Watchlist'; $mode = 'WATCHLIST';
        } elseif (!$confirmed) {
            $label = $side . ' BIAS - WAIT FOR CONFIRMATION'; $action = 'WAIT'; $readiness = 'Confirmation Required'; $mode = 'CONFIRMATION_REQUIRED';
        } else {
            $label = $side . ' CONFIRMED'; $action = $side; $readiness = 'Execution Ready'; $mode = 'CONFIRMED';
        }

        $riskHigh = in_array($newsRisk, ['HIGH','CRITICAL','EXTREME'], true) || in_array($geoRisk, ['HIGH','CRITICAL','EXTREME'], true);
        if ($riskHigh && $mode === 'CONFIRMED') $mode = 'CONFIRMED_RISK_CAUTION';

        return [
            'action' => $action,
            'label' => $label,
            'tone' => $action === 'WAIT' ? 'amber' : ($side === 'BUY' ? 'emerald' : 'red'),
            'execution_mode' => $mode,
            'score_10' => $score,
            'score_100' => round($score * 10, 1),
            'raw_score_100' => $primary['raw_score'] ?? round($score * 10, 1),
            'confidence' => self::confidence($score, $confirmationStage),
            'grade' => self::grade($score),
            'readiness' => $readiness,
            'summary' => $label,
            'primary_side' => $action === 'WAIT' ? 'WAIT' : $side,
            'scenario_side' => $side,
            'secondary_side' => $secondary['side'] ?? '',
            'confirmation_stage' => $confirmationStage,
            'hard_block' => $action === 'WAIT',
            'directional_conflict' => false,
        ];
    }

    private static function isTradeable(array $scenario, array $context): bool
    {
        $stage = strtoupper((string)($context['confirmation_stage'] ?? 'CONFIRMATION_PENDING'));
        $count = (int)($context['confirmation_count'] ?? 0);
        return (float)($scenario['score_10'] ?? 0) >= 6.5
            && ($stage === 'EXECUTION_CONFIRMED' || $count >= 4)
            && !empty($scenario['zone'])
            && !empty($scenario['fresh_entry_valid']);
    }

    private static function readiness(float $score, string $stage, int $confirmed, int $partial): string
    {
        if ($stage === 'EXECUTION_CONFIRMED' || $confirmed >= 4) return 'Execution Ready';
        if ($score >= 5.5) return 'Confirmation Required';
        if ($partial > 0 || $confirmed > 0) return 'Developing Setup';
        return 'Watchlist';
    }

    private static function confidence(float $score10, string $stage): string
    {
        if ($score10 >= 8.5) return $stage === 'EXECUTION_CONFIRMED' ? 'VERY HIGH' : 'HIGH';
        if ($score10 >= 7.0) return 'HIGH';
        if ($score10 >= 5.5) return 'MEDIUM';
        if ($score10 >= 4.5) return 'LOW';
        return 'VERY LOW';
    }

    private static function grade(float $score10): string
    {
        if ($score10 >= 8.5) return 'A';
        if ($score10 >= 7.0) return 'B+';
        if ($score10 >= 5.5) return 'B';
        if ($score10 >= 4.5) return 'C+';
        return 'C';
    }

    private static function num($value, float $fallback = 0.0): float
    {
        return is_numeric($value) ? (float)$value : $fallback;
    }
}
