"""Phaxor — Column Buckling Engine (Python port)"""

import math

K_FACTORS = {
    'pinned-pinned': 1.0,
    'fixed-free': 2.0,
    'fixed-pinned': 0.7,
    'fixed-fixed': 0.5,
}


def calc_column_section(section_type: str, dims: dict) -> dict:
    """Calculate cross-section area (mm²), moment of inertia (mm⁴), and radius of gyration (mm)."""
    A = 0
    I = 0

    if section_type == 'solid-circle':
        d = dims.get('d', 0)
        A = math.pi * d**2 / 4
        I = math.pi * d**4 / 64
    elif section_type == 'hollow-circle':
        D = dims.get('D', 0)
        di = dims.get('di', 0)
        A = math.pi * (D**2 - di**2) / 4
        I = math.pi * (D**4 - di**4) / 64
    elif section_type == 'solid-rectangle':
        b = dims.get('b', 0)
        h = dims.get('h', 0)
        A = b * h
        I = min(b * h**3, h * b**3) / 12
    elif section_type == 'i-beam':
        bf = dims.get('bf', 0)
        tf = dims.get('tf', 0)
        hw = dims.get('hw', 0)
        tw = dims.get('tw', 0)
        A = 2 * bf * tf + hw * tw
        Iy = 2 * tf * bf**3 / 12 + hw * tw**3 / 12
        Ix = 2 * (bf * tf**3 / 12 + bf * tf * ((hw + tf) / 2)**2) + tw * hw**3 / 12
        I = min(Ix, Iy)

    r = math.sqrt(I / A) if A > 0 else 0
    return {'A': A, 'I': I, 'r': r}


def solve_column_buckling(inputs: dict) -> dict | None:
    """Euler & Johnson column buckling analysis."""
    L = inputs.get('length', 0)
    E_GPa = inputs.get('E', 200)
    I_val = inputs.get('I', 0)
    A = inputs.get('area', 0)
    end_cond = inputs.get('endCondition', 'pinned-pinned')
    P = inputs.get('appliedLoad', 0)
    sigma_y = inputs.get('yieldStrength', 250)
    K = K_FACTORS.get(end_cond, 1.0)
    E_MPa = E_GPa * 1000

    if L <= 0 or A <= 0 or I_val <= 0:
        return None

    r = math.sqrt(I_val / A)
    Le = K * L
    SR = Le / r
    Cc = math.sqrt(2 * math.pi**2 * E_MPa / sigma_y)

    if SR >= Cc:
        critical_stress = math.pi**2 * E_MPa / SR**2
    else:
        critical_stress = sigma_y * (1 - (sigma_y * SR**2) / (4 * math.pi**2 * E_MPa))

    critical_load = critical_stress * A
    safety_factor = critical_load / P if P > 0 else float('inf')

    return {
        'effectiveLength': Le,
        'slendernessRatio': SR,
        'criticalLoad': critical_load / 1000,
        'criticalStress': critical_stress,
        'safetyFactor': safety_factor,
        'bucklingSafe': safety_factor >= 2.0,
        'radiusOfGyration': r,
        'kFactor': K,
    }
