"""Phaxor — Belt Drive Calculation Engine (Python port)"""
import math

BELT_TYPES = {
    'v-belt': {'label': 'V-Belt', 'efficiency': 95, 'maxSpeed': 30, 'frictionCoeff': 0.50, 'maxRatio': 8},
    'timing': {'label': 'Timing / Synchronous', 'efficiency': 98, 'maxSpeed': 60, 'frictionCoeff': 0, 'maxRatio': 10},
    'flat': {'label': 'Flat Belt', 'efficiency': 96, 'maxSpeed': 50, 'frictionCoeff': 0.35, 'maxRatio': 6},
    'poly-v': {'label': 'Poly-V (Multi-Rib)', 'efficiency': 97, 'maxSpeed': 40, 'frictionCoeff': 0.45, 'maxRatio': 12},
    'round': {'label': 'Round Belt', 'efficiency': 90, 'maxSpeed': 10, 'frictionCoeff': 0.30, 'maxRatio': 4},
}


def solve_belt_drive(inputs: dict) -> dict | None:
    """Solve belt drive geometry, speeds, and tensions."""
    belt_type_key = inputs.get('beltType', 'v-belt')
    d1 = float(inputs.get('d1', 0))
    d2 = float(inputs.get('d2', 0))
    center_dist = float(inputs.get('centerDist', 0))
    driver_rpm = float(inputs.get('driverRPM', 0))
    power = float(inputs.get('power', 0))
    service_factor = float(inputs.get('serviceFactor', 1.0))

    if d1 <= 0 or d2 <= 0 or center_dist <= 0:
        return None

    bt = BELT_TYPES.get(belt_type_key, BELT_TYPES['v-belt'])

    ratio = d2 / d1
    n2 = driver_rpm / ratio

    # Belt length
    term1 = 2 * center_dist
    term2 = (math.pi / 2) * (d1 + d2)
    term3 = math.pow(d2 - d1, 2) / (4 * center_dist)
    belt_length = term1 + term2 + term3

    # Wrap angle
    sin_arg = abs(d2 - d1) / (2 * center_dist)
    safe_sin_arg = max(-1, min(1, sin_arg))
    wrap_small = 180 - (2 * math.asin(safe_sin_arg) * 180 / math.pi)
    wrap_large = 360 - wrap_small

    # Contact arc
    r_small = min(d1, d2) / 2
    contact_arc = (r_small * wrap_small * math.pi) / 180

    # Belt speed
    belt_speed = (math.pi * (d1 / 1000) * driver_rpm) / 60

    # Effective pull
    f_eff = (power * 1000) / belt_speed if belt_speed > 0 else 0

    if belt_type_key == 'timing':
        t1 = f_eff * 1.1
        t2 = t1 - f_eff
    else:
        theta_rad = wrap_small * math.pi / 180
        mu = bt['frictionCoeff']
        exp_mu_theta = math.exp(mu * theta_rad)
        if exp_mu_theta > 1:
            t1 = f_eff * (exp_mu_theta) / (exp_mu_theta - 1)
        else:
            t1 = f_eff * 2
        t2 = max(0, t1 - f_eff)

    mass_per_length = 0.1
    if belt_type_key == 'v-belt': mass_per_length = 0.15
    elif belt_type_key == 'poly-v': mass_per_length = 0.12
    elif belt_type_key == 'flat': mass_per_length = 0.08

    tc = mass_per_length * belt_speed * belt_speed

    design_power = power * service_factor
    efficiency = bt['efficiency']
    output_power = power * (efficiency / 100)

    input_torque = (power * 1000 * 60) / (2 * math.pi * driver_rpm) if driver_rpm > 0 else 0
    output_torque = (output_power * 1000 * 60) / (2 * math.pi * n2) if n2 > 0 else 0

    return {
        'ratio': float(f"{ratio:.3f}"),
        'n2': float(f"{n2:.1f}"),
        'beltLength': float(f"{belt_length:.1f}"),
        'wrapSmall': float(f"{wrap_small:.1f}"),
        'wrapLarge': float(f"{wrap_large:.1f}"),
        'contactArc': float(f"{contact_arc:.1f}"),
        'beltSpeed': float(f"{belt_speed:.2f}"),
        'Feff': float(f"{f_eff:.1f}"),
        'T1': float(f"{t1:.1f}"),
        'T2': float(f"{t2:.1f}"),
        'Tc': float(f"{tc:.1f}"),
        'designPower': float(f"{design_power:.2f}"),
        'efficiency': efficiency,
        'outputPower': float(f"{output_power:.3f}"),
        'outputTorque': float(f"{output_torque:.2f}"),
        'inputTorque': float(f"{input_torque:.2f}"),
        'warnings': {
            'wrapLow': wrap_small < 120,
            'speedHigh': belt_speed > bt['maxSpeed'],
            'ratioHigh': ratio > bt['maxRatio']
        }
    }
