"""Phaxor — Failure Theory Engine (Python port)"""
import math

def solve_failure_theory(inputs: dict) -> dict:
    """
    Calculate Factor of Safety (FOS) based on various failure theories.
    Input keys:
      stress: { sigma1, sigma2, sigma3 }
      material: { Sy, Sut, Suc }
    """
    stress = inputs.get('stress', {})
    material = inputs.get('material', {})
    
    sigma1 = stress.get('sigma1', 0)
    sigma2 = stress.get('sigma2', 0)
    sigma3 = stress.get('sigma3', 0)
    
    Sy = material.get('Sy', 250)
    Sut = material.get('Sut', 400)
    Suc = material.get('Suc', 400)
    
    # Sort principal stresses: s1 > s2 > s3
    sorted_stresses = sorted([sigma1, sigma2, sigma3], reverse=True)
    s1, s2, s3 = sorted_stresses[0], sorted_stresses[1], sorted_stresses[2]
    
    results = []
    
    # 1. Maximum Principal Stress (Rankine)
    max_principal = max(abs(s1), abs(s3))
    strength = Sut if s1 >= 0 else Suc
    # Logic from TS: fos = (s1 >= 0 ? Sut : Suc) / maxPrincipal
    # Actually TS logic: const maxPrincipal = Math.max(Math.abs(s1), Math.abs(s3));
    # const fosMPS = maxPrincipal > 0 ? (s1 >= 0 ? Sut : Suc) / maxPrincipal : Infinity;
    # Wait, if s1 < 0 (all compressive), maxPrincipal is abs(s3). 
    # If s1 >= 0, we use Sut. If s1 < 0, we use Suc. 
    # This assumes if s1 < 0, then ALL are negative, so failure is compressive.
    fos_mps = float('inf')
    if max_principal > 0:
        limit = Sut if s1 >= 0 else Suc
        fos_mps = limit / max_principal
    
    results.append({
        'name': 'Max Principal Stress (Rankine)',
        'abbrev': 'MPS',
        'fos': abs(fos_mps),
        'safe': abs(fos_mps) >= 1,
        'criterion': f"|σ_max| ≤ S_y → {max_principal:.1f} ≤ {Sy}",
        'description': 'Best for brittle materials. Failure when max principal stress reaches ultimate strength.',
        'color': '#3b82f6'
    })
    
    # 2. Maximum Shear Stress (Tresca)
    tau_max_tresca = (s1 - s3) / 2
    fos_tresca = Sy / (2 * tau_max_tresca) if tau_max_tresca != 0 else float('inf')
    
    results.append({
        'name': 'Max Shear Stress (Tresca)',
        'abbrev': 'Tresca',
        'fos': abs(fos_tresca),
        'safe': abs(fos_tresca) >= 1,
        'criterion': f"τ_max ≤ S_y/2 → {tau_max_tresca:.1f} ≤ {(Sy / 2):.1f}",
        'description': 'Conservative for ductile materials. Hexagonal yield envelope.',
        'color': '#f59e0b'
    })
    
    # 3. Distortion Energy (von Mises)
    von_mises = math.sqrt(0.5 * ((s1 - s2)**2 + (s2 - s3)**2 + (s3 - s1)**2))
    fos_vm = Sy / von_mises if von_mises != 0 else float('inf')
    
    results.append({
        'name': 'Distortion Energy (von Mises)',
        'abbrev': 'von Mises',
        'fos': abs(fos_vm),
        'safe': abs(fos_vm) >= 1,
        'criterion': f"σ_vm ≤ S_y → {von_mises:.1f} ≤ {Sy}",
        'description': 'Most accurate for ductile materials. Elliptical yield envelope.',
        'color': '#10b981'
    })
    
    # 4. Coulomb-Mohr (Modified Mohr)
    fos_cm = float('inf')
    if s1 >= 0 and s3 >= 0:
        fos_cm = Sut / s1 if s1 != 0 else float('inf')
    elif s1 <= 0 and s3 <= 0:
        fos_cm = Suc / abs(s3) if s3 != 0 else float('inf')
    else:
        denom = (s1 / Sut) - (s3 / Suc)
        fos_cm = 1 / denom if denom != 0 else float('inf')
        
    results.append({
        'name': 'Coulomb-Mohr Theory',
        'abbrev': 'C-Mohr',
        'fos': abs(fos_cm),
        'safe': abs(fos_cm) >= 1,
        'criterion': f"σ₁/S_ut - σ₃/S_uc ≤ 1 → {(s1 / Sut - s3 / Suc):.3f} ≤ 1",
        'description': 'For materials with different tension/compression strengths (cast iron, concrete).',
        'color': '#a855f7'
    })
    
    return {
        'result': results,
        'steps': [f"Sorted Principal Stresses: σ1={s1}, σ2={s2}, σ3={s3}"]
    }
