#!/usr/bin/env python3
import os
import time
import unittest

import cereal.messaging as messaging
import system.sensord.pigeond as pd

from common.params import Params
from system.hardware import TICI
from selfdrive.manager.process_config import managed_processes
from selfdrive.test.helpers import with_processes


def wait_for_location(sm, timeout, con=10):
  cons_meas = 0
  start_time = time.monotonic()
  while (time.monotonic() - start_time) < timeout:
    sm.update()
    if not sm.updated["gnssMeasurements"]:
      continue

    msg = sm["gnssMeasurements"]
    cons_meas = (cons_meas + 1) if 'positionECEF' in msg.to_dict() else 0
    if cons_meas >= con:
      return True
  return False


class TestLaikad(unittest.TestCase):
  @classmethod
  def setUpClass(self):
    if not TICI:
      raise unittest.SkipTest

    ublox_available = Params().get_bool("UbloxAvailable")
    if not ublox_available:
      raise unittest.SkipTest

  def setUp(self):
    # ensure laikad cold start
    Params().remove("LaikadEphemerisV3")
    os.environ["LAIKAD_NO_INTERNET"] = "1"
    managed_processes['laikad'].start()

  def tearDown(self):
    managed_processes['laikad'].stop()


  @with_processes(['pigeond', 'ubloxd'])
  def test_laikad_cold_start(self):
    time.sleep(5)

    start_time = time.monotonic()
    sm = messaging.SubMaster(["gnssMeasurements"])

    success = wait_for_location(sm, 60*2, con=10)
    duration = time.monotonic() - start_time

    assert success, "Waiting for location timed out (2min)!"
    assert duration < 60, f"Received Location {duration}!"


  @with_processes(['ubloxd'])
  def test_laikad_ublox_reset_start(self):
    time.sleep(2)

    pigeon, pm = pd.create_pigeon()
    pd.init_baudrate(pigeon)
    assert pigeon.reset_device(), "Could not reset device!"

    laikad_sock = messaging.sub_sock("gnssMeasurements", timeout=0.1)
    ublox_gnss_sock = messaging.sub_sock("ubloxGnss", timeout=0.1)

    pd.init_baudrate(pigeon)
    pd.initialize_pigeon(pigeon)
    pd.run_receiving(pigeon, pm, 180)

    ublox_msgs = messaging.drain_sock(ublox_gnss_sock)
    laikad_msgs = messaging.drain_sock(laikad_sock)

    gps_ephem_cnt = 0
    glonass_ephem_cnt = 0
    for um in ublox_msgs:
      if um.ubloxGnss.which() == 'ephemeris':
        gps_ephem_cnt += 1
      elif um.ubloxGnss.which() == 'glonassEphemeris':
        glonass_ephem_cnt += 1

    assert gps_ephem_cnt > 0, "NO gps ephemeris collected!"
    assert glonass_ephem_cnt > 0, "NO glonass ephemeris collected!"

    pos_meas = 0
    duration = -1
    for lm in laikad_msgs:
      pos_meas = (pos_meas + 1) if 'positionECEF' in lm.gnssMeasurements.to_dict() else 0
      if pos_meas > 5:
        duration = (lm.logMonoTime - laikad_msgs[0].logMonoTime)*1e-9
        break

    assert pos_meas > 5, "NOT enough positions at end of read!"
    assert duration < 120, "Laikad took too long to get a Position!"

if __name__ == "__main__":
  unittest.main()
