from dataclasses import dataclass
from functools import cached_property
import math
from scipy import optimize

from apc_perf import RPM, ApcPerfdata

VOLT_DUTY_MAX = 0.97

@dataclass(frozen=True)
class MotorOppoint:
    voltage: float
    current: float
    rpm: float
    torque: float

    @cached_property
    def rot_speed(self) -> float:
        return self.rpm * RPM
    
    @property
    def power_in(self) -> float:
        return self.voltage * self.current

    @property
    def power_out(self) -> float:
        return self.torque * self.rot_speed
    
    @property
    def efficiency(self) -> float:
        return self.power_out/self.power_in

@dataclass(frozen=True)
class MotorData:
    mot_kv: float
    mot_ir: float
    mot_idle_i: float

    @cached_property
    def mot_kv_si(self) -> float:
        return self.mot_kv * RPM

    @property
    def effective_ir(self) -> float:
        return self.mot_ir*1.5
        return self.mot_ir

    def mot_full_pizda(self, rpm: float, voltage: float) -> MotorOppoint:
        rotspd = rpm * RPM
        voltage = VOLT_DUTY_MAX * voltage
        u_active = (rotspd / self.mot_kv_si)
        u_heat = voltage - u_active
        current = u_heat / self.effective_ir
        torq = (current-self.mot_idle_i) / self.mot_kv_si

        return MotorOppoint(
                voltage = voltage,
                current = current,
                rpm = rpm,
                torque = torq,
                )



def op_full_pizda(mot: MotorData, prop: ApcPerfdata, speed: float, volt: float):

    def f(rpm):
        return prop.get_op_interp(rpm, speed).torque - mot.mot_full_pizda(rpm, volt).torque

    opt = optimize.root_scalar(f, bracket = prop.rpm_range_at_speed(speed))
    # print(opt)

    rpm = opt.root

    p_op = prop.get_op_interp(rpm, speed)
    m_op = mot.mot_full_pizda(rpm, volt)
    # print(p_op)
    # print(m_op)

    return p_op, m_op




