#!/usr/bin/env python3
import sys
import math
import datetime
from collections import Counter
from pprint import pprint
from typing import cast

from cereal.services import SERVICE_LIST
from openpilot.tools.lib.logreader import LogReader, ReadMode
from openpilot.selfdrive.test.process_replay.migration import migrate_all

if __name__ == "__main__":
  cnt_events: Counter = Counter()

  cams = [s for s in SERVICE_LIST if s.endswith('CameraState')]
  cnt_cameras = dict.fromkeys(cams, 0)

  events: list[tuple[float, set[str]]] = []
  alerts: list[tuple[float, str]] = []
  start_time = math.inf
  end_time = -math.inf
  ignition_off = None
  for msg in migrate_all(LogReader(sys.argv[1], ReadMode.QLOG)):
    t = (msg.logMonoTime - start_time) / 1e9
    end_time = max(end_time, msg.logMonoTime)
    start_time = min(start_time, msg.logMonoTime)

    if msg.which() == 'onroadEvents':
      for e in msg.onroadEvents:
        cnt_events[e.name] += 1

      ae = {str(e.name) for e in msg.onroadEvents if e.name not in ('pedalPressed', 'steerOverride', 'gasPressedOverride')}
      if len(events) == 0 or ae != events[-1][1]:
        events.append((t, ae))

    elif msg.which() == 'selfdriveState':
      at = msg.selfdriveState.alertType
      if "/override" not in at or "lanechange" in at.lower():
        if len(alerts) == 0 or alerts[-1][1] != at:
          alerts.append((t, at))
    elif msg.which() == 'pandaStates':
      if ignition_off is None:
        ign = any(ps.ignitionLine or ps.ignitionCan for ps in msg.pandaStates)
        if not ign:
          ignition_off = msg.logMonoTime
          break
    elif msg.which() in cams:
      cnt_cameras[msg.which()] += 1

  duration = (end_time - start_time) / 1e9

  print("Events")
  pprint(cnt_events)

  print("\n")
  print("Events")
  for t, evt in events:
    print(f"{t:8.2f} {evt}")

  print("\n")
  print("Cameras")
  for k, v in cnt_cameras.items():
    s = SERVICE_LIST[k]
    expected_frames = int(s.frequency * duration / cast(float, s.decimation))
    print("  ", k.ljust(20), f"{v}, {v/expected_frames:.1%} of expected")

  print("\n")
  print("Alerts")
  for t, a in alerts:
    print(f"{t:8.2f} {a}")

  print("\n")
  if ignition_off is not None:
    ignition_off = round((ignition_off - start_time) / 1e9, 2)
  print("Ignition off at",  ignition_off)
  print("Route duration", datetime.timedelta(seconds=duration))
