"""
Physical unit conversions for laser control module.

Converts between physical quantities (°C, mA, V) and
raw ADC/DAC integer values used by the device firmware.

All formulas are taken directly from the original device_conversion.py.
"""

import math
from .constants import (
    VREF, R1, R3, R4, R5, R6,
    R7, R8, R9, R10,
    RREF,
    BETA_INTERNAL, BETA_EXTERNAL, T0_K, R0,
    ADC_BITS_16, ADC_BITS_12,
    U3V3_COEFF, U5V_COEFF, U7V_COEFF,
)


def temp_c_to_n(temp_c: float) -> int:
    """
    Convert temperature (°C) to 16-bit DAC integer (Wheatstone bridge setpoint).

    Args:
        temp_c: Temperature in degrees Celsius.

    Returns:
        Integer in [0, 65535] for the DAC.
    """
    rt = R0 * math.exp(BETA_INTERNAL / (temp_c + 273) - BETA_INTERNAL / T0_K)
    u = VREF / (R5 * (R3 + R4)) * (
        R1 * R4 * (R5 + R6) - rt * (R3 * R6 - R4 * R5)
    ) / (rt + R1)
    n = int(u * ADC_BITS_16 / VREF)
    n = max(0, min(ADC_BITS_16, n))
    return n


def temp_n_to_c(n: int) -> float:
    """
    Convert 16-bit ADC integer to temperature (°C).

    Args:
        n: Raw ADC value in [0, 65535].

    Returns:
        Temperature in degrees Celsius.
    """
    u = n * VREF / ADC_BITS_16
    rt = R1 * (VREF * R4 * (R5 + R6) - u * R5 * (R3 + R4)) / (
        u * R5 * (R3 + R4) + VREF * R3 * R6 - VREF * R4 * R5
    )
    t = 1 / (1 / T0_K + 1 / BETA_INTERNAL * math.log(rt / R0)) - 273
    return t


def temp_ext_n_to_c(n: int) -> float:
    """
    Convert 12-bit ADC integer to external thermistor temperature (°C).

    Args:
        n: Raw 12-bit ADC value in [0, 4095].

    Returns:
        Temperature in degrees Celsius.
    """
    u = n * VREF / ADC_BITS_12 * 1 / (1 + 100000 / R10) + VREF * R9 / (R8 + R9)
    rt = R7 * u / (VREF - u)
    t = 1 / (1 / T0_K + 1 / BETA_EXTERNAL * math.log(rt / R0)) - 273
    return t


def current_ma_to_n(current_ma: float) -> int:
    """
    Convert laser drive current (mA) to 16-bit DAC integer.

    Args:
        current_ma: Current in milliamps.

    Returns:
        Integer in [0, 65535] for the DAC.
    """
    n = int(ADC_BITS_16 / 2000 * RREF * current_ma)
    n = max(0, min(ADC_BITS_16, n))
    return n


def current_n_to_ma(n: int) -> float:
    """
    Convert raw ADC integer to photodiode current (mA).

    Args:
        n: Raw ADC value in [0, 65535].

    Returns:
        Current in milliamps.
    """
    return n * 2.5 / (ADC_BITS_16 * 4.4) - 1 / 20.4


def voltage_3v3_n_to_v(n: int) -> float:
    """Convert 3.3V rail ADC count to volts."""
    return n * U3V3_COEFF


def voltage_5v_n_to_v(n: int) -> float:
    """Convert 5V rail ADC count to volts (both 5V1 and 5V2)."""
    return n * U5V_COEFF


def voltage_7v_n_to_v(n: int) -> float:
    """Convert 7V rail ADC count to volts."""
    return n * U7V_COEFF