"""MockLink -- a synthetic ElmLink for tests and GUI development without a
truck.  Simulates a cranking 6.0: ICP ramps toward ~540 psi, FICM holds ~48V,
battery sags, MAP/BARO sit at atmospheric.  Same read interface as ElmLink.
"""


class MockLink:
    def __init__(self, clock):
        self.clock = clock                  # callable -> float seconds
        self.t0 = clock()
        self.protocol = "A6"

    def init(self):
        pass

    def fast_timing(self, on=True):
        pass

    def connect(self):
        return True

    def is_can(self):
        return True

    def _u16le(self, raw16):
        return [(raw16 >> 8) & 0xFF, raw16 & 0xFF]

    def read_m22(self, pid, timeout=0.5):
        el = self.clock() - self.t0
        if pid == "1446":                   # ICP: ramps 0 -> 540 over ~2.7s
            return self._u16le(int(min(540, el * 200) / 0.57))
        if pid == "09D0":                   # FICM main ~48V (0x3000)
            return self._u16le(0x3000)
        if pid == "1440":                   # MAP atmospheric
            return [0x01, 0x89]
        if pid == "1442":                   # BARO atmospheric
            return [0x01, 0x88]
        if pid == "1445":                   # EBP atmospheric
            return [0x01, 0x8F]
        if pid == "1310":                   # EOT ~33C
            return [0x1C, 0x92]
        return None                         # everything else: no response

    def read_m01(self, pid, nbytes, timeout=0.6):
        if pid == "0C":                     # RPM ~750 idle
            v = 750 * 4
            return [(v >> 8) & 0xFF, v & 0xFF]
        if pid == "05":                     # ECT 82C
            return [122]
        if pid == "0D":                     # speed 48 km/h
            return [48]
        if pid == "10":                     # MAF 12.0 g/s
            v = 1200
            return [(v >> 8) & 0xFF, v & 0xFF]
        if pid == "01":                     # readiness: MIL off, 0 DTCs, mixed monitors
            return [0x00, 0x07, 0x61, 0x20]
        return None

    def read_atrv(self, timeout=0.8):
        el = self.clock() - self.t0
        return 10.6 if el < 2.5 else 12.5   # crank sag then recover

    def read_dtcs(self, mode, svc, timeout=5.0):
        return ["P0148"] if mode == "03" else []

    def clear_dtcs(self):
        return True

    def read_vehicle_info(self, timeout=2.0):
        return {"vin": "1FMZU73E12ZA12345", "calibration": "JR3A-12A650-BCD",
                "ecu_name": "ECM-EngineControl"}

    def read_readiness(self, timeout=1.0):
        from . import obdservices as svc
        return svc.decode_readiness([0x00, 0x07, 0x61, 0x20])

    def read_freeze_frame(self, timeout=0.6):
        return {"dtc": "P0148",
                "values": [("Engine RPM", 240, "rpm"), ("Coolant Temp", 33, "C"),
                           ("Engine Load", 18, "%"), ("Vehicle Speed", 0, "km/h")]}

    def read_raw(self, hexcmd, timeout=2.0):
        # Return a UDS positive response (sid+0x40) so actions succeed in mock.
        h = hexcmd.replace(" ", "")
        sid = int(h[:2], 16)
        rest = [int(h[i:i + 2], 16) for i in range(2, len(h) - 1, 2)]
        if sid == 0x27 and len(rest) == 1:          # security seed request -> return a seed
            return [0x67, rest[0], 0x11, 0x22, 0x33, 0x44]
        return [(sid + 0x40) & 0xFF] + rest

    def close(self):
        pass
