"""Phaxor — Heat Exchanger Engine (Python port)"""
import math

def solve_heat_exchanger(inputs: dict) -> dict | None:
    """Heat Exchanger Calculator (LMTD & NTU)."""
    method = inputs.get('method', 'lmtd')
    flow_arr = inputs.get('flowArrangement', 'counter')
    th_in = float(inputs.get('Th_in', 0))
    tc_in = float(inputs.get('Tc_in', 0))
    mh = float(inputs.get('mh', 0))
    mc = float(inputs.get('mc', 0))
    cph = float(inputs.get('cph', 0))
    cpc = float(inputs.get('cpc', 0))
    u = float(inputs.get('U', 0))

    if mh <= 0 or mc <= 0 or cph <= 0 or cpc <= 0 or u <= 0:
        return None

    ch = mh * cph
    cc = mc * cpc
    cmin = min(ch, cc)
    cmax = max(ch, cc)
    cr = cmin / cmax if cmax > 0 else 0

    q_max = cmin * (th_in - tc_in)

    if method == 'lmtd':
        th_out = float(inputs.get('Th_out', 0))
        tc_out = float(inputs.get('Tc_out', 0))
        
        q = ch * (th_in - th_out)
        
        if flow_arr == 'counter':
            dt1 = th_in - tc_out
            dt2 = th_out - tc_in
        else:
            dt1 = th_in - tc_in
            dt2 = th_out - tc_out

        dt1s = max(dt1, 0.01)
        dt2s = max(dt2, 0.01)
        
        if abs(dt1s - dt2s) < 0.1:
            lmtd = (dt1s + dt2s) / 2
        else:
            lmtd = (dt1s - dt2s) / math.log(dt1s / dt2s)

        area = q / (u * lmtd) if lmtd > 0 else 0
        effectiveness = q / q_max if q_max > 0 else 0
        ntu = (u * area) / cmin

        return {
            'method': 'LMTD',
            'LMTD': float(f"{lmtd:.1f}"),
            'NTU': float(f"{ntu:.2f}"),
            'effectiveness': float(f"{effectiveness:.3f}"),
            'Q': float(f"{q:.1f}"),
            'area': float(f"{area:.2f}"),
            'Tc_out': float(f"{tc_out:.1f}"),
            'Th_out': float(f"{th_out:.1f}"),
            'Cmin': float(f"{cmin:.0f}"),
            'Cmax': float(f"{cmax:.0f}"),
            'Cr': float(f"{cr:.3f}"),
            'Qmax': float(f"{q_max:.1f}")
        }

    else:
        # NTU Method
        area = float(inputs.get('area', 0))
        if area <= 0:
            return None

        ntu = (u * area) / cmin

        eps = 0.0
        if flow_arr == 'counter':
            if abs(cr - 1) < 0.001:
                eps = ntu / (1 + ntu)
            else:
                exp_val = math.exp(-ntu * (1 - cr))
                eps = (1 - exp_val) / (1 - cr * exp_val)
        else:
            exp_val = math.exp(-ntu * (1 + cr))
            eps = (1 - exp_val) / (1 + cr)
        
        eps = max(0.0, min(1.0, eps))

        q = eps * q_max
        th_out_calc = th_in - q / ch
        tc_out_calc = tc_in + q / cc
        
        if area > 0:
             lmtd = q / (u * area)
        else:
             lmtd = 0

        return {
            'method': 'ε-NTU',
            'LMTD': float(f"{lmtd:.1f}"),
            'NTU': float(f"{ntu:.2f}"),
            'effectiveness': float(f"{eps:.3f}"),
            'Q': float(f"{q:.1f}"),
            'area': float(f"{area:.2f}"),
            'Tc_out': float(f"{tc_out_calc:.1f}"),
            'Th_out': float(f"{th_out_calc:.1f}"),
            'Cmin': float(f"{cmin:.0f}"),
            'Cmax': float(f"{cmax:.0f}"),
            'Cr': float(f"{cr:.3f}"),
            'Qmax': float(f"{q_max:.1f}")
        }
