<?php

declare(strict_types=1);

namespace App\Services;

use Illuminate\Support\Collection;

class KycRiskCalculator
{
    /**
     * KYC Risk Level Schwellenwerte (3 Levels)
     */
    private const RISK_THRESHOLDS = [
        'low' => 20,      // 0-20 = Geringes Risiko (nur saubere EU/OECD Transaktionen ohne Red Flags)
        'high' => 50,     // 20-50 = Hohes Risiko (Tax Havens, High-Risk Countries, PEP, Corruption)
        'critical' => 100, // 50-100 = Kritisches Risiko (Sanctions, Multiple Red Flags, Structuring)
    ];

    /**
     * Gewichtung der verschiedenen Risk-Faktoren
     */
    private const RISK_WEIGHTS = [
        'transaction_score' => 0.15,      // 15% Gewichtung (reduziert für mehr Raum bei kritischen Faktoren)
        'transaction_analysis' => 0.15,   // 15% Gewichtung (duplicate, structuring, fake purpose)
        'sanctions' => 0.25,              // 25% Gewichtung (ERHÖHT - sehr kritisch!)
        'country_risk' => 0.15,           // 15% Gewichtung (ERHÖHT - wichtiger Indikator)
        'pep_adverse' => 0.10,            // 10% Gewichtung (ERHÖHT - staatliche Verbindungen)
        'corruption' => 0.10,             // 10% Gewichtung (ERHÖHT - Korruption ist kritisch)
        'financial_health' => 0.07,       // 7% Gewichtung (insolvency, liquidation, rating)
        'legal_issues' => 0.03,           // 3% Gewichtung (court cases, tax haven, export violations)
    ];

    /**
     * Berechne KYC Risk Level basierend auf Transaction Outputs (Legacy - verwendet Entity)
     *
     * @param  Collection  $outputs  Collection von backend_data_pool records für eine Transaction
     * @return string 'low', 'high', or 'critical'
     */
    public function calculateKycRiskLevel(Collection $outputs): string
    {
        return $this->calculateEntityKycRiskLevel($outputs);
    }

    /**
     * Berechne Entity KYC Risk Level (sendende Partei)
     *
     * @param  Collection  $outputs  Collection von backend_data_pool records
     * @return string 'low', 'high', or 'critical'
     */
    public function calculateEntityKycRiskLevel(Collection $outputs): string
    {
        $breakdown = $this->calculateEntityKycRiskBreakdown($outputs);

        return $breakdown['risk_level'];
    }

    /**
     * Berechne Entity KYC Risk Level mit detailliertem Breakdown
     *
     * @param  Collection  $outputs  Collection von backend_data_pool records
     * @return array Breakdown mit scores und risk_level
     */
    public function calculateEntityKycRiskBreakdown(Collection $outputs): array
    {
        if ($outputs->isEmpty()) {
            return [
                'risk_level' => 'high',
                'weighted_score' => 70.0,
                'scores' => [],
            ];
        }

        $outputsArray = $outputs->pluck('content', 'output_key')->toArray();

        $scores = [
            'transaction_score' => $this->calculateTransactionScore($outputsArray),
            'transaction_analysis' => $this->calculateTransactionAnalysisScore($outputsArray),
            'sanctions' => $this->calculateSanctionsScore($outputsArray, 'entity_'),
            'country_risk' => $this->calculateCountryRiskScore($outputsArray, 'entity_'),
            'pep_adverse' => $this->calculatePepAdverseScore($outputsArray, 'entity_'),
            'corruption' => $this->calculateCorruptionScore($outputsArray, 'entity_'),
            'financial_health' => $this->calculateFinancialHealthScore($outputsArray, 'entity_'),
            'legal_issues' => $this->calculateLegalIssuesScore($outputsArray, 'entity_'),
        ];

        $weightedScore = $this->calculateWeightedScore($scores);
        $riskLevel = $this->determineRiskLevel($weightedScore);

        return [
            'risk_level' => $riskLevel,
            'weighted_score' => round($weightedScore, 2),
            'scores' => $scores,
        ];
    }

    /**
     * Berechne Counterparty KYC Risk Level (empfangende Partei)
     *
     * @param  Collection  $outputs  Collection von backend_data_pool records
     * @return string 'low', 'high', or 'critical'
     */
    public function calculateCounterpartyKycRiskLevel(Collection $outputs): string
    {
        $breakdown = $this->calculateCounterpartyKycRiskBreakdown($outputs);

        return $breakdown['risk_level'];
    }

    /**
     * Berechne Counterparty KYC Risk Level mit detailliertem Breakdown
     *
     * @param  Collection  $outputs  Collection von backend_data_pool records
     * @return array Breakdown mit scores und risk_level
     */
    public function calculateCounterpartyKycRiskBreakdown(Collection $outputs): array
    {
        if ($outputs->isEmpty()) {
            return [
                'risk_level' => 'high',
                'weighted_score' => 70.0,
                'scores' => [],
            ];
        }

        $outputsArray = $outputs->pluck('content', 'output_key')->toArray();

        $scores = [
            'transaction_score' => $this->calculateTransactionScore($outputsArray),
            'transaction_analysis' => $this->calculateTransactionAnalysisScore($outputsArray),
            'sanctions' => $this->calculateSanctionsScore($outputsArray, 'counterparty_'),
            'country_risk' => $this->calculateCountryRiskScore($outputsArray, 'counterparty_'),
            'pep_adverse' => $this->calculatePepAdverseScore($outputsArray, 'counterparty_'),
            'corruption' => $this->calculateCorruptionScore($outputsArray, 'counterparty_'),
            'financial_health' => $this->calculateFinancialHealthScore($outputsArray, 'counterparty_'),
            'legal_issues' => $this->calculateLegalIssuesScore($outputsArray, 'counterparty_'),
        ];

        $weightedScore = $this->calculateWeightedScore($scores);
        $riskLevel = $this->determineRiskLevel($weightedScore);

        return [
            'risk_level' => $riskLevel,
            'weighted_score' => round($weightedScore, 2),
            'scores' => $scores,
        ];
    }

    /**
     * Berechne Transaction Score (0-100)
     */
    private function calculateTransactionScore(array $outputs): int
    {
        if (! isset($outputs['tranx_score'])) {
            return 60; // Default: Hohes Risiko wenn keine Daten
        }

        $scoreData = json_decode($outputs['tranx_score'], true);

        // Format: {"score": 75}
        if (is_array($scoreData) && isset($scoreData['score'])) {
            return min(100, max(0, (int) $scoreData['score']));
        }

        // Format: {"risk_level": "high"}
        if (is_array($scoreData) && isset($scoreData['risk_level'])) {
            return $this->mapRiskLevelToScore($scoreData['risk_level']);
        }

        // Falls nur numerischer Wert
        if (is_numeric($scoreData)) {
            return min(100, max(0, (int) $scoreData));
        }

        return 60; // Default
    }

    /**
     * Berechne Sanctions Score (0-100)
     */
    private function calculateSanctionsScore(array $outputs, string $prefix = ''): int
    {
        $sanctionFlags = [
            $prefix.'corporate_eusanctions',
            $prefix.'corporate_ofacsanctions',
            $prefix.'corporate_uksanctions',
            $prefix.'sanctions_circumvention',
        ];

        $score = 0;
        $foundSanctions = 0;

        foreach ($sanctionFlags as $flag) {
            if (! isset($outputs[$flag])) {
                continue;
            }

            $data = json_decode($outputs[$flag], true);

            if ($this->hasSanctionsMatch($data)) {
                $foundSanctions++;

                if (is_array($data) && isset($data['severity'])) {
                    $score += $this->mapSeverityToScore($data['severity']);
                } else {
                    $score += 70; // Default: Hohes Risiko
                }
            }
        }

        if ($foundSanctions === 0) {
            return 0;
        }

        $avgScore = $score / $foundSanctions;

        // Mehrere Sanctions → Kritisches Risiko
        if ($foundSanctions > 1) {
            return min(100, (int) round($avgScore * 1.3));
        }

        return (int) round($avgScore);
    }

    /**
     * Berechne Country Risk Score (0-100)
     */
    private function calculateCountryRiskScore(array $outputs, string $prefix = ''): int
    {
        $key = $prefix.'country_risk';

        // Wenn Country Risk Daten vorhanden sind, diese verwenden
        if (isset($outputs[$key])) {
            $countryRiskData = json_decode($outputs[$key], true);

            // Prüfe ob flag=true ist (valide Daten vorhanden)
            if (is_array($countryRiskData) && isset($countryRiskData['flag']) && $countryRiskData['flag'] === true) {
                if (isset($countryRiskData['score'])) {
                    return min(100, max(0, (int) $countryRiskData['score']));
                }

                if (isset($countryRiskData['level'])) {
                    return $this->mapRiskLevelToScore($countryRiskData['level']);
                }
            }
        }

        // FALLBACK: Versuche Land aus HQ oder anderen Feldern zu extrahieren
        $countryCode = $this->extractCountryCodeFromOutputs($outputs, $prefix);

        if ($countryCode) {
            return $this->getCountryRiskScoreByCode($countryCode);
        }

        return 40; // Default: Mittleres Risiko
    }

    /**
     * Extrahiere Ländercode aus verfügbaren Daten
     */
    private function extractCountryCodeFromOutputs(array $outputs, string $prefix): ?string
    {
        // Bekannte Länder-Mappings (WICHTIG: Zuerst Länder-Namen matchen!)
        $countryPatterns = [
            '/\bAzerbaijan\b/i' => 'AZ',
            '/\bGermany\b/i' => 'DE',
            '/\bDeutschland\b/i' => 'DE',
            '/\bRussia\b/i' => 'RU',
            '/\bChina\b/i' => 'CN',
            '/\bUnited States\b/i' => 'US',
            '/\bKazakhstan\b/i' => 'KZ',
            '/\bTurkmenistan\b/i' => 'TM',
            '/\bVenezuela\b/i' => 'VE',
            '/\bIran\b/i' => 'IR',
            '/\bNorth Korea\b/i' => 'KP',
            '/\bBelarus\b/i' => 'BY',
            '/\bCuba\b/i' => 'CU',
            '/\bMyanmar\b/i' => 'MM',
            '/\bSyria\b/i' => 'SY',
            '/\bAfghanistan\b/i' => 'AF',
            '/\bYemen\b/i' => 'YE',
            '/\bSomalia\b/i' => 'SO',
            '/\bSudan\b/i' => 'SD',
            '/\b(?:British )?Virgin Islands\b/i' => 'VG', // British Virgin Islands (Tax Haven)
            '/\bCayman Islands\b/i' => 'KY', // Cayman Islands (Tax Haven)
            '/\bBermuda\b/i' => 'BM', // Bermuda (Tax Haven)
            '/\bBahamas\b/i' => 'BS', // Bahamas (Tax Haven)
            '/\bPanama\b/i' => 'PA', // Panama (Tax Haven)
            '/\bLiechtenstein\b/i' => 'LI', // Liechtenstein (Tax Haven)
            '/\bMonaco\b/i' => 'MC', // Monaco (Tax Haven)
            '/\bLuxembourg\b/i' => 'LU', // Luxembourg (Tax Haven)
        ];

        // HIGHEST PRIORITY: Check corporate_name field (company name often contains country)
        $nameKey = $prefix.'corporate_name';
        if (isset($outputs[$nameKey])) {
            $nameData = json_decode($outputs[$nameKey], true);
            if (is_array($nameData) && isset($nameData['answer'])) {
                foreach ($countryPatterns as $pattern => $code) {
                    if (preg_match($pattern, $nameData['answer'])) {
                        return $code;
                    }
                }
            }
        }

        // Versuche aus summary zu extrahieren (zweite Priorität)
        $summaryKey = $prefix.'corporate_summary';
        if (isset($outputs[$summaryKey])) {
            $summaryData = json_decode($outputs[$summaryKey], true);
            if (is_array($summaryData) && isset($summaryData['answer'])) {
                $answer = $summaryData['answer'];

                foreach ($countryPatterns as $pattern => $code) {
                    if (preg_match($pattern, $answer)) {
                        return $code;
                    }
                }
            }
        }

        // Versuche aus HQ zu extrahieren
        $hqKey = $prefix.'corporate_HQ';
        if (isset($outputs[$hqKey])) {
            $hqData = json_decode($outputs[$hqKey], true);
            if (is_array($hqData) && isset($hqData['answer'])) {
                $answer = $hqData['answer'];

                // Erst Länder-Namen matchen
                foreach ($countryPatterns as $pattern => $code) {
                    if (preg_match($pattern, $answer)) {
                        return $code;
                    }
                }

                // Falls keine Länder-Namen gefunden: Suche nach 2-Buchstaben Ländercodes
                // ABER: Exclude common false positives wie "AG" (Aktiengesellschaft)
                $excludePatterns = ['AG', 'SA', 'AB', 'CO', 'LT', 'LP', 'PC', 'UK']; // UK ist OK, aber später
                if (preg_match('/\b([A-Z]{2})\b/', $answer, $matches)) {
                    $potentialCode = $matches[1];
                    if (! in_array($potentialCode, $excludePatterns)) {
                        return $potentialCode;
                    }
                }
            }
        }

        return null;
    }

    /**
     * Bestimme Country Risk Score basierend auf Ländercode (Fallback)
     */
    private function getCountryRiskScoreByCode(string $countryCode): int
    {
        // Kritische Hochrisikoländer (Sanktionen, Terror)
        $criticalRiskCountries = [
            'KP' => 95, // Nordkorea
            'IR' => 95, // Iran
            'SY' => 95, // Syrien
            'AF' => 90, // Afghanistan
            'YE' => 90, // Jemen
            'SO' => 90, // Somalia
            'SD' => 85, // Sudan
        ];

        // Hochrisikoländer (Sanktionen, Korruption, Geldwäsche)
        $highRiskCountries = [
            'RU' => 85, // Russland
            'BY' => 85, // Belarus
            'VE' => 85, // Venezuela
            'CU' => 80, // Kuba
            'MM' => 80, // Myanmar
            'ZW' => 80, // Simbabwe
            'LY' => 80, // Libyen
            'IQ' => 75, // Irak
        ];

        // Erhöhtes Risiko (Korruption, schwache Governance, Öl-Staaten)
        $mediumHighRiskCountries = [
            'AZ' => 70, // Aserbaidschan (Öl, Korruption) ← WICHTIG!
            'KZ' => 70, // Kasachstan
            'TM' => 70, // Turkmenistan
            'UZ' => 65, // Usbekistan
            'TJ' => 65, // Tadschikistan
            'PK' => 65, // Pakistan
            'BD' => 60, // Bangladesch
            'NG' => 65, // Nigeria
            'CD' => 70, // DR Kongo
            'GQ' => 75, // Äquatorialguinea
            'AO' => 65, // Angola
            'GN' => 65, // Guinea
            'HT' => 70, // Haiti
            'NI' => 65, // Nicaragua
            'ER' => 75, // Eritrea
            'LA' => 60, // Laos
            'KH' => 60, // Kambodscha
            'CN' => 55, // China (Governance, Menschenrechte)
        ];

        // Steueroasen (ERHÖHT für strengere Bewertung - Tax Havens sind hohes AML-Risiko!)
        $taxHavens = [
            'KY' => 75, // Cayman Islands (stark erhöht)
            'BM' => 75, // Bermuda (stark erhöht)
            'VG' => 80, // British Virgin Islands (stark erhöht - sehr häufig für Briefkastenfirmen)
            'BS' => 75, // Bahamas (stark erhöht)
            'PA' => 80, // Panama (stark erhöht - Panama Papers)
            'LI' => 70, // Liechtenstein
            'MC' => 65, // Monaco
            'LU' => 60, // Luxembourg (trotz EU - Steueroase)
        ];

        // Prüfe Kritisch
        if (isset($criticalRiskCountries[$countryCode])) {
            return $criticalRiskCountries[$countryCode];
        }

        // Prüfe Hoch
        if (isset($highRiskCountries[$countryCode])) {
            return $highRiskCountries[$countryCode];
        }

        // Prüfe Mittel-Hoch
        if (isset($mediumHighRiskCountries[$countryCode])) {
            return $mediumHighRiskCountries[$countryCode];
        }

        // Prüfe Steueroasen
        if (isset($taxHavens[$countryCode])) {
            return $taxHavens[$countryCode];
        }

        // EU & OECD Länder = Geringes Risiko
        $lowRiskCountries = [
            'DE', 'FR', 'IT', 'ES', 'NL', 'BE', 'AT', 'CH', 'SE', 'NO', 'DK', 'FI',
            'GB', 'IE', 'PT', 'GR', 'PL', 'CZ', 'HU', 'RO', 'BG', 'SK', 'SI', 'HR',
            'LT', 'LV', 'EE', 'CY', 'MT', 'LU', 'IS',
            'US', 'CA', 'AU', 'NZ', 'JP', 'KR', 'SG',
        ];

        if (in_array($countryCode, $lowRiskCountries)) {
            return 25; // Geringes Risiko
        }

        return 40; // Default: Mittleres Risiko
    }

    /**
     * Berechne PEP & Adverse Media Score (0-100)
     */
    private function calculatePepAdverseScore(array $outputs, string $prefix = ''): int
    {
        $score = 0;
        $count = 0;

        $pepFields = [
            $prefix.'corporate_pepexposure' => 75,
            $prefix.'corporate_pep' => 80,
            $prefix.'corporate_adverse' => 70,
            $prefix.'corporate_AMLexposure' => 85,
        ];

        foreach ($pepFields as $field => $defaultScore) {
            if (! isset($outputs[$field])) {
                continue;
            }

            $data = json_decode($outputs[$field], true);

            // Prüfe zuerst auf flag=true
            if ($this->hasPositiveMatch($data)) {
                $score += $this->extractScoreFromData($data, $defaultScore);
                $count++;
            } elseif (is_array($data) && isset($data['answer'])) {
                // FALLBACK: Wenn flag=false, aber Answer enthält PEP-Keywords
                $answer = strtolower($data['answer']);

                // PEP-Keywords (state-owned, government, politically exposed, etc.)
                $pepKeywords = [
                    'politically exposed person',
                    'state-owned',
                    'state owned',
                    'government official',
                    'government-owned',
                    'public official',
                    'may be considered pep',
                    'pep proximity',
                    'close associate',
                ];

                // Adverse Media Keywords
                $adverseKeywords = [
                    'bribery',
                    'corruption',
                    'scandal',
                    'allegation',
                    'investigation',
                    'money laundering',
                    'fraud',
                    'sanctions',
                ];

                // Prüfe auf Keywords
                foreach ($pepKeywords as $keyword) {
                    if (stripos($answer, $keyword) !== false) {
                        // PEP-Indikator gefunden, aber mit reduziertem Score (da flag=false)
                        $score += $defaultScore * 0.7; // 70% des Default Scores
                        $count++;
                        break; // Nur einmal pro Feld zählen
                    }
                }

                // Wenn noch nicht gezählt, prüfe auf Adverse Keywords
                if ($count === 0 || ! isset($scored)) {
                    foreach ($adverseKeywords as $keyword) {
                        if (stripos($answer, $keyword) !== false) {
                            $score += $defaultScore * 0.6; // 60% bei Adverse Keywords
                            $count++;
                            break;
                        }
                    }
                }
            }
        }

        return $count > 0 ? (int) round($score / $count) : 0;
    }

    /**
     * Berechne Corruption Score (0-100)
     */
    private function calculateCorruptionScore(array $outputs, string $prefix = ''): int
    {
        $corruptionFields = [
            $prefix.'corruption_sector',
            $prefix.'corruption_country',
            $prefix.'corruption_relationship',
            $prefix.'corporate_corruptionexposure',
        ];

        $totalScore = 0;
        $count = 0;

        foreach ($corruptionFields as $field) {
            if (! isset($outputs[$field])) {
                continue;
            }

            $data = json_decode($outputs[$field], true);

            if ($this->hasPositiveMatch($data)) {
                $totalScore += $this->extractScoreFromData($data, 70);
                $count++;
            }
        }

        return $count > 0 ? (int) round($totalScore / $count) : 0;
    }

    /**
     * Berechne gewichteten Gesamt-Score
     */
    private function calculateWeightedScore(array $scores): float
    {
        $totalScore = 0.0;

        foreach ($scores as $category => $score) {
            $weight = self::RISK_WEIGHTS[$category] ?? 0;
            $totalScore += $score * $weight;
        }

        return $totalScore;
    }

    /**
     * Bestimme Risk Level basierend auf Score (3 Levels)
     */
    private function determineRiskLevel(float $score): string
    {
        if ($score <= self::RISK_THRESHOLDS['low']) {
            return 'low';  // Geringes Risiko
        }

        if ($score <= self::RISK_THRESHOLDS['high']) {
            return 'high';  // Hohes Risiko
        }

        return 'critical';  // Kritisches Risiko
    }

    /**
     * Hilfsfunktionen
     */
    private function mapRiskLevelToScore(string $level): int
    {
        return match (strtolower($level)) {
            'low', 'green', 'gering', 'geringes risiko' => 25,
            'high', 'yellow', 'orange', 'hoch', 'hohes risiko' => 60,
            'critical', 'red', 'kritisch', 'kritisches risiko' => 85,
            default => 60,
        };
    }

    private function mapSeverityToScore(string $severity): int
    {
        return match (strtolower($severity)) {
            'minor', 'low', 'gering' => 40,
            'moderate', 'high', 'hoch' => 65,
            'critical', 'severe', 'kritisch' => 90,
            default => 65,
        };
    }

    private function hasSanctionsMatch($data): bool
    {
        if (! is_array($data)) {
            return false;
        }

        return (isset($data['matches']) && ! empty($data['matches']))
            || (isset($data['found']) && $data['found'] === true)
            || (isset($data['sanctioned']) && $data['sanctioned'] === true)
            || (isset($data['flag']) && $data['flag'] === true); // WICHTIG: Flag-Check hinzugefügt
    }

    private function hasPositiveMatch($data): bool
    {
        if (is_array($data)) {
            return (isset($data['match']) && $data['match'] === true)
                || (isset($data['found']) && $data['found'] === true)
                || (isset($data['matches']) && ! empty($data['matches']))
                || (isset($data['exposure']) && $data['exposure'] === true)
                || (isset($data['flag']) && $data['flag'] === true); // WICHTIG: Flag-Check hinzugefügt
        }

        if (is_bool($data)) {
            return $data;
        }

        return false;
    }

    private function extractScoreFromData($data, int $default): int
    {
        if (is_array($data) && isset($data['score'])) {
            return min(100, max(0, (int) $data['score']));
        }

        if (is_array($data) && isset($data['risk_score'])) {
            return min(100, max(0, (int) $data['risk_score']));
        }

        return $default;
    }

    /**
     * Berechne Transaction Plausibility Score (0-100)
     * Analysiert die Plausibilität der Transaktion basierend auf:
     * - Betragshöhe
     * - Länder-Kombination
     * - Zweck
     * - Währung
     */
    public function calculateTransactionPlausibilityScore(array $transactionData): int
    {
        $riskFactors = [];
        $score = 0; // Start bei 0 = kein Risiko

        // 1. Betragshöhe analysieren
        $amount = (float) ($transactionData['tx_amount'] ?? 0);
        if ($amount > 10000000) { // > 10 Mio
            $riskFactors[] = 40; // Sehr hohe Beträge = erhöhtes Risiko
        } elseif ($amount > 1000000) { // > 1 Mio
            $riskFactors[] = 25;
        } elseif ($amount > 100000) { // > 100k
            $riskFactors[] = 15;
        } else {
            $riskFactors[] = 5; // Kleine Beträge = geringes Risiko
        }

        // 2. Länder-Kombination analysieren
        $outgoing = $transactionData['tx_country_outgoing'] ?? '';
        $incoming = $transactionData['tx_country_incoming'] ?? '';

        // Kritische Hochrisikoländer (Sanktionen, Terror, schwere Korruption)
        $criticalRiskCountries = [
            'KP', // Nordkorea
            'IR', // Iran
            'SY', // Syrien
            'AF', // Afghanistan (Taliban)
            'YE', // Jemen
            'SO', // Somalia
            'SD', // Sudan
        ];

        // Hochrisikoländer (Sanktionen, Korruption, Geldwäsche)
        $highRiskCountries = [
            'RU', // Russland
            'BY', // Belarus
            'VE', // Venezuela
            'CU', // Kuba
            'MM', // Myanmar
            'ZW', // Simbabwe
            'LY', // Libyen
            'IQ', // Irak
        ];

        // Erhöhtes Risiko (Korruption, schwache Governance, Öl-Staaten)
        $mediumHighRiskCountries = [
            'AZ', // Aserbaidschan (Öl, Korruption)
            'KZ', // Kasachstan (Öl, Korruption)
            'TM', // Turkmenistan (Öl, Diktatur)
            'UZ', // Usbekistan
            'TJ', // Tadschikistan
            'PK', // Pakistan
            'BD', // Bangladesch
            'NG', // Nigeria (Korruption, Öl)
            'CD', // DR Kongo
            'GQ', // Äquatorialguinea (Öl, Diktatur)
            'AO', // Angola (Öl, Korruption)
            'GN', // Guinea
            'HT', // Haiti
            'NI', // Nicaragua
            'ER', // Eritrea
            'LA', // Laos
            'KH', // Kambodscha
        ];

        // Steueroasen & Offshore-Zentren
        $taxHavens = [
            'KY', // Cayman Islands
            'BM', // Bermuda
            'VG', // British Virgin Islands
            'BS', // Bahamas
            'PA', // Panama
            'LI', // Liechtenstein
            'MC', // Monaco
            'AN', // Niederländische Antillen
            'AG', // Antigua und Barbuda
            'BZ', // Belize
            'SC', // Seychellen
            'MU', // Mauritius
            'WS', // Samoa
            'CK', // Cook Islands
            'IM', // Isle of Man
            'JE', // Jersey
            'GG', // Guernsey
            'MT', // Malta (teilweise)
            'CY', // Zypern (teilweise)
        ];

        // China separat bewerten (wegen Größe und wirtschaftlicher Bedeutung)
        $chinaRelated = ['CN', 'HK', 'MO']; // China, Hong Kong, Macau

        // Risiko-Bewertung nach Priorität
        if (in_array($outgoing, $criticalRiskCountries) || in_array($incoming, $criticalRiskCountries)) {
            $riskFactors[] = 70; // Kritisches Risiko
        } elseif (in_array($outgoing, $highRiskCountries) || in_array($incoming, $highRiskCountries)) {
            $riskFactors[] = 50; // Hohes Risiko
        } elseif (in_array($outgoing, $taxHavens) || in_array($incoming, $taxHavens)) {
            $riskFactors[] = 45; // Steueroase
        } elseif (in_array($outgoing, $mediumHighRiskCountries) || in_array($incoming, $mediumHighRiskCountries)) {
            $riskFactors[] = 35; // Erhöhtes Risiko (Korruption, schwache Governance)
        } elseif (in_array($outgoing, $chinaRelated) || in_array($incoming, $chinaRelated)) {
            $riskFactors[] = 30; // China: Moderates Risiko (Kapitalkontrolle, Transparenz)
        } else {
            $riskFactors[] = 10; // Normale Länder (EU, USA, entwickelte Demokratien)
        }

        // 3. Zweck analysieren (Verdächtige Keywords)
        $purpose = strtolower($transactionData['tx_purpose'] ?? '');
        $suspiciousKeywords = ['cash', 'loan', 'investment', 'consulting', 'service fee', 'commission'];

        $suspiciousCount = 0;
        foreach ($suspiciousKeywords as $keyword) {
            if (str_contains($purpose, $keyword)) {
                $suspiciousCount++;
            }
        }

        if ($suspiciousCount >= 2) {
            $riskFactors[] = 30; // Mehrere verdächtige Keywords
        } elseif ($suspiciousCount === 1) {
            $riskFactors[] = 15;
        } else {
            $riskFactors[] = 5;
        }

        // 4. Währungs-Plausibilität
        $currency = $transactionData['tx_currency'] ?? 'EUR';
        if (! in_array($currency, ['EUR', 'USD', 'GBP', 'CHF', 'JPY'])) {
            $riskFactors[] = 20; // Unübliche Währung
        } else {
            $riskFactors[] = 5;
        }

        // Berechne Durchschnitt aller Risikofaktoren
        $score = (int) round(array_sum($riskFactors) / count($riskFactors));

        return min(100, max(0, $score));
    }

    /**
     * Berechne kombinierten Risk Score mit Entity, Counterparty und Transaction Plausibility
     * KATEGORISCHER ANSATZ: Höheres Risiko schlägt niedrigeres
     * - Wenn IRGENDEIN Faktor CRITICAL → Gesamt CRITICAL
     * - Wenn IRGENDEIN Faktor HIGH → Gesamt HIGH
     * - Sonst → LOW
     *
     * @return array ['entity_risk_level', 'counterparty_risk_level', 'plausibility_score', 'plausibility_level', 'combined_score', 'combined_risk_level', 'entity_risk_breakdown', 'counterparty_risk_breakdown', 'transaction_plausibility_breakdown', 'combined_risk_breakdown']
     */
    public function calculateCombinedRisk(Collection $outputs, array $transactionData): array
    {
        // Berechne Entity Risk mit Breakdown
        $entityBreakdown = $this->calculateEntityKycRiskBreakdown($outputs);
        $entityRiskLevel = $entityBreakdown['risk_level'];

        // Berechne Counterparty Risk mit Breakdown
        $counterpartyBreakdown = $this->calculateCounterpartyKycRiskBreakdown($outputs);
        $counterpartyRiskLevel = $counterpartyBreakdown['risk_level'];

        // Berechne Transaction Plausibility Score und konvertiere zu Level
        $plausibilityScore = $this->calculateTransactionPlausibilityScore($transactionData);
        $plausibilityLevel = $this->determineRiskLevel($plausibilityScore);

        // KATEGORISCHER ANSATZ: Critical schlägt High schlägt Low
        $combinedRiskLevel = $this->determineCategoricalRiskLevel([
            $entityRiskLevel,
            $counterpartyRiskLevel,
            $plausibilityLevel,
        ]);

        // Konvertiere finales Risk Level zu Score für die Datenbank
        $combinedScore = $this->riskLevelToNumericScore($combinedRiskLevel);

        // Transaction Plausibility Breakdown
        $transactionPlausibilityBreakdown = [
            'score' => $plausibilityScore,
            'risk_level' => $plausibilityLevel,
            'transaction_data' => $transactionData,
        ];

        // Combined Risk Breakdown
        $combinedRiskBreakdown = [
            'combined_risk_level' => $combinedRiskLevel,
            'combined_score' => $combinedScore,
            'method' => 'categorical',
            'contributing_factors' => [
                'entity_risk_level' => $entityRiskLevel,
                'counterparty_risk_level' => $counterpartyRiskLevel,
                'plausibility_level' => $plausibilityLevel,
            ],
        ];

        return [
            'entity_risk_level' => $entityRiskLevel,
            'counterparty_risk_level' => $counterpartyRiskLevel,
            'plausibility_score' => $plausibilityScore,
            'plausibility_level' => $plausibilityLevel,
            'combined_score' => $combinedScore,
            'combined_risk_level' => $combinedRiskLevel,
            // Neue Breakdown-Daten
            'entity_risk_breakdown' => $entityBreakdown,
            'counterparty_risk_breakdown' => $counterpartyBreakdown,
            'transaction_plausibility_breakdown' => $transactionPlausibilityBreakdown,
            'combined_risk_breakdown' => $combinedRiskBreakdown,
        ];
    }

    /**
     * Bestimme kategorisches Risk Level: Höchstes Risiko gewinnt
     * CRITICAL > HIGH > LOW
     *
     * @param  array  $riskLevels  Array von Risk Levels ['low', 'high', 'critical']
     * @return string 'low', 'high', or 'critical'
     */
    private function determineCategoricalRiskLevel(array $riskLevels): string
    {
        // Wenn IRGENDEIN Faktor CRITICAL → Gesamt CRITICAL
        if (in_array('critical', $riskLevels)) {
            return 'critical';
        }

        // Wenn IRGENDEIN Faktor HIGH → Gesamt HIGH
        if (in_array('high', $riskLevels)) {
            return 'high';
        }

        // Sonst → LOW
        return 'low';
    }

    /**
     * Konvertiere Risk Level zu numerischem Score (0-100)
     */
    private function riskLevelToNumericScore(string $riskLevel): int
    {
        return match ($riskLevel) {
            'low' => 20,
            'high' => 60,
            'critical' => 90,
            default => 50,
        };
    }

    /**
     * Berechne aggregierten Risk Level für eine Company basierend auf allen Transaktionen
     */
    public function calculateCompanyRiskLevel(Collection $transactions): string
    {
        if ($transactions->isEmpty()) {
            return 'high'; // Default: Hohes Risiko wenn keine Daten
        }

        $riskScores = [
            'low' => 0,
            'high' => 0,
            'critical' => 0,
        ];

        // Zähle Risk Levels aller Transaktionen
        foreach ($transactions as $transactionOutputs) {
            $riskLevel = $this->calculateKycRiskLevel($transactionOutputs);
            $riskScores[$riskLevel]++;
        }

        $totalTransactions = $transactions->count();

        // Worst-Case-Prinzip:
        // 1. Wenn EINE Transaktion kritisches Risiko hat → Company ist kritisch
        if ($riskScores['critical'] > 0) {
            return 'critical';
        }

        // 2. Wenn >30% der Transaktionen hohes Risiko haben → Company ist kritisch
        $highRiskPercentage = $riskScores['high'] / $totalTransactions;
        if ($highRiskPercentage > 0.3) {
            return 'critical';
        }

        // 3. Wenn >10% hohes Risiko → Company ist hohes Risiko
        if ($highRiskPercentage > 0.1) {
            return 'high';
        }

        // 4. Wenn >80% geringes Risiko → Company ist geringes Risiko
        if ($riskScores['low'] / $totalTransactions > 0.8) {
            return 'low';
        }

        // 5. Default: Hohes Risiko (vorsichtig)
        return 'high';
    }

    /**
     * NEU: Berechne Transaction Analysis Score (0-100)
     * Analysiert: Duplikate, Structuring/Smurfing, Fake Purpose
     */
    private function calculateTransactionAnalysisScore(array $outputs): int
    {
        $score = 0;
        $flagCount = 0;

        // 1. Duplikats-Erkennung
        if (isset($outputs['tranx_duplicate'])) {
            $data = json_decode($outputs['tranx_duplicate'], true);
            if ($this->hasPositiveMatch($data)) {
                $score += 85; // Duplikate = sehr hohes Risiko
                $flagCount++;
            }
        }

        // 2. Structuring/Smurfing Detection (Geldwäsche-Indikator)
        if (isset($outputs['tranx_structuring'])) {
            $data = json_decode($outputs['tranx_structuring'], true);
            if ($this->hasPositiveMatch($data)) {
                $score += 95; // Structuring = kritisches Risiko
                $flagCount++;
            }
        }

        // 3. Fake Purpose Check
        if (isset($outputs['tranx_fakepurposecheck'])) {
            $data = json_decode($outputs['tranx_fakepurposecheck'], true);
            if ($this->hasPositiveMatch($data)) {
                $score += 80; // Fake Purpose = hohes Risiko
                $flagCount++;
            }
        }

        // 4. Round Amount (Rundbeträge können auf Geldwäsche hindeuten)
        if (isset($outputs['tranx_roundamount'])) {
            $data = json_decode($outputs['tranx_roundamount'], true);
            if ($this->hasPositiveMatch($data)) {
                $score += 40; // Rundbeträge = mittleres Risiko
                $flagCount++;
            }
        }

        // 5. Velocity Check (zu schnelle/viele Transaktionen)
        if (isset($outputs['tranx_velocitycheck'])) {
            $data = json_decode($outputs['tranx_velocitycheck'], true);
            if ($this->hasPositiveMatch($data)) {
                $score += 70; // Velocity = hohes Risiko
                $flagCount++;
            }
        }

        // 6. Unusual Pattern
        if (isset($outputs['tranx_unusualpattern'])) {
            $data = json_decode($outputs['tranx_unusualpattern'], true);
            if ($this->hasPositiveMatch($data)) {
                $score += 60; // Ungewöhnliche Muster = erhöhtes Risiko
                $flagCount++;
            }
        }

        if ($flagCount === 0) {
            return 0; // Keine verdächtigen Muster gefunden
        }

        // Durchschnitt berechnen
        return (int) round($score / $flagCount);
    }

    /**
     * NEU: Berechne Financial Health Score (0-100)
     * Analysiert: Insolvenz, Liquidation, Rating, Solvency
     */
    private function calculateFinancialHealthScore(array $outputs, string $prefix = ''): int
    {
        $score = 0;
        $flagCount = 0;

        // 1. Insolvenz (kritisch)
        if (isset($outputs[$prefix.'corporate_insolvency'])) {
            $data = json_decode($outputs[$prefix.'corporate_insolvency'], true);
            if ($this->hasPositiveMatch($data)) {
                $score += 95; // Insolvenz = kritisches Risiko
                $flagCount++;
            }
        }

        // 2. Liquidation (kritisch)
        if (isset($outputs[$prefix.'corporate_liquidation'])) {
            $data = json_decode($outputs[$prefix.'corporate_liquidation'], true);
            if ($this->hasPositiveMatch($data)) {
                $score += 95; // Liquidation = kritisches Risiko
                $flagCount++;
            }
        }

        // 3. Rating (falls vorhanden)
        if (isset($outputs[$prefix.'corporate_rating'])) {
            $data = json_decode($outputs[$prefix.'corporate_rating'], true);

            if (is_array($data) && isset($data['rating'])) {
                $rating = strtoupper($data['rating']);

                // Rating-basierte Scores
                if (in_array($rating, ['D', 'C', 'CC', 'CCC'])) {
                    $score += 90; // Sehr schlechtes Rating
                    $flagCount++;
                } elseif (in_array($rating, ['B', 'BB', 'BBB'])) {
                    $score += 60; // Mittleres Rating
                    $flagCount++;
                } elseif (in_array($rating, ['A', 'AA', 'AAA'])) {
                    $score += 10; // Gutes Rating (geringes Risiko)
                    $flagCount++;
                }
            }
        }

        // 4. Solvency (Zahlungsfähigkeit)
        if (isset($outputs[$prefix.'corporate_solvency'])) {
            $data = json_decode($outputs[$prefix.'corporate_solvency'], true);

            if (is_array($data) && isset($data['solvent']) && $data['solvent'] === false) {
                $score += 85; // Nicht zahlungsfähig = hohes Risiko
                $flagCount++;
            }
        }

        // 5. Audit Findings (Prüfungsfeststellungen)
        if (isset($outputs[$prefix.'corporate_auditfindings'])) {
            $data = json_decode($outputs[$prefix.'corporate_auditfindings'], true);

            if (is_array($data) && isset($data['critical_findings']) && $data['critical_findings'] === true) {
                $score += 70; // Kritische Prüfungsfeststellungen
                $flagCount++;
            }
        }

        if ($flagCount === 0) {
            return 0; // Keine finanziellen Probleme gefunden
        }

        return (int) round($score / $flagCount);
    }

    /**
     * NEU: Berechne Legal Issues Score (0-100)
     * Analysiert: Gerichtsverfahren, Steueroasen, Exportverstöße, Warnungen
     */
    private function calculateLegalIssuesScore(array $outputs, string $prefix = ''): int
    {
        $score = 0;
        $flagCount = 0;

        // 1. Court Cases (Gerichtsverfahren)
        if (isset($outputs[$prefix.'corporate_courtcases'])) {
            $data = json_decode($outputs[$prefix.'corporate_courtcases'], true);

            if (is_array($data) && isset($data['active_cases']) && $data['active_cases'] > 0) {
                $caseCount = (int) $data['active_cases'];

                if ($caseCount >= 5) {
                    $score += 80; // Viele Verfahren = hohes Risiko
                } elseif ($caseCount >= 2) {
                    $score += 60; // Einige Verfahren = mittleres Risiko
                } else {
                    $score += 40; // Ein Verfahren = erhöhtes Risiko
                }
                $flagCount++;
            }
        }

        // 2. Tax Haven (Steueroasen-Nutzung)
        if (isset($outputs[$prefix.'corporate_haven'])) {
            $data = json_decode($outputs[$prefix.'corporate_haven'], true);
            if ($this->hasPositiveMatch($data)) {
                $score += 75; // Steueroasen = hohes Risiko
                $flagCount++;
            }
        }

        // 3. Export Control Violations (Exportverstöße)
        if (isset($outputs[$prefix.'corporate_exportcontrol'])) {
            $data = json_decode($outputs[$prefix.'corporate_exportcontrol'], true);
            if ($this->hasPositiveMatch($data)) {
                $score += 90; // Exportverstöße = kritisches Risiko
                $flagCount++;
            }
        }

        // 4. Warnings (Behördliche Warnungen)
        if (isset($outputs[$prefix.'corporate_warnings'])) {
            $data = json_decode($outputs[$prefix.'corporate_warnings'], true);
            if ($this->hasPositiveMatch($data)) {
                $score += 70; // Warnungen = hohes Risiko
                $flagCount++;
            }
        }

        // 5. License Issues (Lizenzprobleme)
        if (isset($outputs[$prefix.'corporate_license'])) {
            $data = json_decode($outputs[$prefix.'corporate_license'], true);

            if (is_array($data) && isset($data['license_valid']) && $data['license_valid'] === false) {
                $score += 65; // Ungültige/fehlende Lizenz = erhöhtes Risiko
                $flagCount++;
            }
        }

        if ($flagCount === 0) {
            return 0; // Keine rechtlichen Probleme gefunden
        }

        return (int) round($score / $flagCount);
    }
}
