#!/usr/bin/env python3
"""
Fraud/Waste/Abuse (FWA) Risk Scorer

Aggregates multiple risk indicators to calculate fraud risk score
and escalate decision from REVIEW to HIGH-RISK when appropriate.

Version: 1.0
Date: November 2, 2025
"""

from typing import Dict, List, Any, Tuple

class FraudRiskScorer:
    """
    Calculates fraud risk score based on multiple indicators
    """
    
    # Fraud risk thresholds
    HIGH_RISK_THRESHOLD = 50  # Score >= 50 = HIGH-RISK (lowered from 60)
    MEDIUM_RISK_THRESHOLD = 30  # Score >= 30 = ELEVATED-RISK
    
    def calculate_fraud_score(
        self, 
        detected_archetypes: List[str],
        context_factors: Dict,
        claim: Dict,
        confidence: float
    ) -> Tuple[int, str, List[Dict]]:
        """
        Calculate fraud risk score (0-100)
        
        Returns:
            (score, risk_level, indicators)
        """
        score = 0
        indicators = []
        
        # 1. Multiple High-Severity Archetypes (+30 points)
        high_severity_archetypes = [
            'PTP_MUTUALLY_EXCLUSIVE',
            'MUE_VIOLATION',
            'MUE_ANATOMIC',
            'MUE_DUPLICATED_HCPCS',
            'DUPLICATE_DIAGNOSTIC',
            'UNBUNDLING_PATTERN'
        ]
        
        high_severity_count = sum(1 for arch in detected_archetypes if arch in high_severity_archetypes)
        
        if high_severity_count >= 3:
            score += 30
            indicators.append({
                'type': 'MULTIPLE_VIOLATIONS',
                'severity': 'HIGH',
                'description': f'{high_severity_count} high-severity violations detected',
                'points': 30
            })
        elif high_severity_count >= 2:
            score += 20
            indicators.append({
                'type': 'MULTIPLE_VIOLATIONS',
                'severity': 'MEDIUM',
                'description': f'{high_severity_count} high-severity violations detected',
                'points': 20
            })
        
        # 2. High-Dollar Outlier (+25 points)
        amount = claim.get('total_charges', claim.get('charges', {}).get('total', 0))
        
        if amount > 200000:
            score += 25
            indicators.append({
                'type': 'HIGH_DOLLAR_OUTLIER',
                'severity': 'HIGH',
                'description': f'Claim amount ${amount:,.0f} (>$200K)',
                'points': 25
            })
        elif amount > 100000:
            score += 15
            indicators.append({
                'type': 'HIGH_DOLLAR',
                'severity': 'MEDIUM',
                'description': f'Claim amount ${amount:,.0f} (>$100K)',
                'points': 15
            })
        
        # 3. Provider Risk History (+20 points)
        provider_ctx = context_factors.get('2_provider', {})
        provider_denial_rate = provider_ctx.get('provider_denial_rate', 0)
        
        if provider_denial_rate >= 0.80:
            score += 20
            indicators.append({
                'type': 'HIGH_RISK_PROVIDER',
                'severity': 'HIGH',
                'description': f'Provider denial rate: {provider_denial_rate:.0%}',
                'points': 20
            })
        elif provider_denial_rate >= 0.50:
            score += 10
            indicators.append({
                'type': 'ELEVATED_RISK_PROVIDER',
                'severity': 'MEDIUM',
                'description': f'Provider denial rate: {provider_denial_rate:.0%}',
                'points': 10
            })
        
        # 4. Bundling/Duplicate Imaging (+15 points, but avoid double-counting)
        bundling_archetypes = [arch for arch in detected_archetypes if 'BUNDL' in arch]
        duplicate_archetypes = [arch for arch in detected_archetypes if 'DUPLICATE' in arch]
        
        # Only count if we have BOTH bundling AND duplicate (not just multiple bundling)
        if bundling_archetypes and duplicate_archetypes:
            score += 15
            indicators.append({
                'type': 'BUNDLING_AND_DUPLICATE_PATTERN',
                'severity': 'HIGH',
                'description': f'Bundling + duplicate violations detected',
                'points': 15
            })
        elif len(bundling_archetypes) >= 2:
            # Multiple bundling types (but not counted if already in high-severity check)
            if high_severity_count < 2:  # Avoid double-counting
                score += 10
                indicators.append({
                    'type': 'MULTIPLE_BUNDLING_ISSUES',
                    'severity': 'MEDIUM',
                    'description': f'{len(bundling_archetypes)} bundling violations',
                    'points': 10
                })
        
        # 5. MUE Violations (+15 points per violation)
        mue_archetypes = [arch for arch in detected_archetypes if 'MUE' in arch]
        
        if mue_archetypes:
            mue_points = min(len(mue_archetypes) * 15, 30)  # Cap at 30
            score += mue_points
            indicators.append({
                'type': 'MUE_VIOLATIONS',
                'severity': 'HIGH' if len(mue_archetypes) >= 2 else 'MEDIUM',
                'description': f'{len(mue_archetypes)} MUE violation(s): {", ".join(mue_archetypes)}',
                'points': mue_points
            })
        
        # 6. Critical Care with Major Surgery (+10 points)
        procedures = []
        if 'procedure_codes' in claim:
            proc_dict = claim['procedure_codes']
            # ALWAYS convert to strings for consistent comparison
            procedures = [str(v) for v in proc_dict.values() if v]
        
        has_critical_care = any(str(p) in ['99291', '99292'] for p in procedures)
        has_major_surgery = any(str(p) in ['33533', '33534', '33510', '33511'] for p in procedures)
        
        if has_critical_care and has_major_surgery:
            score += 10
            indicators.append({
                'type': 'CRITICAL_CARE_SURGERY_OVERLAP',
                'severity': 'MEDIUM',
                'description': 'Critical care billed with major surgery (potential double-dipping)',
                'points': 10
            })
        
        # 7. Duplicate Diagnostic Imaging (+10 points)
        duplicate_imaging = any(arch in detected_archetypes for arch in ['DUPLICATE_DIAGNOSTIC', 'DUPLICATE_IMAGING'])
        
        if duplicate_imaging:
            score += 10
            indicators.append({
                'type': 'DUPLICATE_IMAGING',
                'severity': 'MEDIUM',
                'description': 'Duplicate diagnostic imaging codes detected',
                'points': 10
            })
        
        # Determine risk level
        # Cap score at 100
        score = min(score, 100)
        
        if score >= self.HIGH_RISK_THRESHOLD:
            risk_level = 'HIGH-RISK'
        elif score >= self.MEDIUM_RISK_THRESHOLD:
            risk_level = 'ELEVATED-RISK'
        else:
            risk_level = 'STANDARD'
        
        return (score, risk_level, indicators)
    
    def should_escalate_decision(
        self,
        fraud_score: int,
        detected_archetypes: List[str],
        amount: float
    ) -> bool:
        """
        Determine if claim should be escalated to HIGH-RISK status
        
        Criteria:
        - Fraud score >= 60, OR
        - 3+ high-severity archetypes AND amount > $100K
        """
        if fraud_score >= self.HIGH_RISK_THRESHOLD:
            return True
        
        high_severity = ['PTP_MUTUALLY_EXCLUSIVE', 'MUE_VIOLATION', 'MUE_ANATOMIC', 
                        'UNBUNDLING_PATTERN', 'DUPLICATE_DIAGNOSTIC']
        high_count = sum(1 for arch in detected_archetypes if arch in high_severity)
        
        if high_count >= 3 and amount > 100000:
            return True
        
        return False

