"""Test cases from the AIAA article."""


# TODO: right formal unit tests.
from __future__ import print_function, with_statement

import datetime as dt
import os
import unittest

import numpy as np

from pyorbital import astronomy, tlefile
from pyorbital.orbital import _SGDP4, Orbital, OrbitElements
from pyorbital.tlefile import ChecksumError


class LineOrbital(Orbital):
    """Read TLE lines instead of file."""

    def __init__(self, satellite, line1, line2):
        """Initialize the class."""
        satellite = satellite.upper()
        self.satellite_name = satellite
        self.tle = tlefile.read(satellite, line1=line1, line2=line2)
        self.orbit_elements = OrbitElements(self.tle)
        self._sgdp4 = _SGDP4(self.orbit_elements)


def get_results(satnumber, delay):
    """Get expected results from result file."""
    path = os.path.dirname(os.path.abspath(__file__))
    with open(os.path.join(path, "aiaa_results")) as f_2:
        line = f_2.readline()
        while line:
            if line.endswith(" xx\n") and int(line[:-3]) == satnumber:
                line = f_2.readline()
                while (not line.startswith("%.8f" % delay)):
                    line = f_2.readline()
                sline = line.split()
                if delay == 0:
                    utc_time = None
                else:
                    utc_time = dt.datetime.strptime(sline[-1], "%H:%M:%S.%f")
                    utc_time = utc_time.replace(year=int(sline[-4]),
                                                month=int(sline[-3]),
                                                day=int(sline[-2]))
                    utc_time = np.datetime64(utc_time)
                return (float(sline[1]),
                        float(sline[2]),
                        float(sline[3]),
                        float(sline[4]),
                        float(sline[5]),
                        float(sline[6]),
                        utc_time)
            line = f_2.readline()


_DATAPATH = os.path.dirname(os.path.abspath(__file__))


class AIAAIntegrationTest(unittest.TestCase):
    """Test against the AIAA test cases."""

    @unittest.skipIf(
        not os.path.exists(os.path.join(_DATAPATH, "SGP4-VER.TLE")),
        "SGP4-VER.TLE not available")
    def test_aiaa(self):
        """Do the tests against AIAA test cases."""
        path = os.path.dirname(os.path.abspath(__file__))
        with open(os.path.join(path, "SGP4-VER.TLE")) as f__:
            test_line = f__.readline()
            while test_line:
                if test_line.startswith("#"):
                    test_name = test_line
                if test_line.startswith("1 "):
                    line1 = test_line
                if test_line.startswith("2 "):
                    _check_line2(f__, test_name, line1, test_line)

                test_line = f__.readline()


def _check_line2(f__, test_name: str, line1: str, test_line: str) -> None:
    line2 = test_line[:69]
    times_str = str.split(test_line[69:])
    times = np.arange(float(times_str[0]),
                      float(times_str[1]) + 1,
                      float(times_str[2]))
    if test_name.startswith("#   SL-14 DEB"):
        # FIXME: we have to handle decaying satellites!
        return

    try:
        o = LineOrbital("unknown", line1, line2)
    except NotImplementedError:
        return
    except ChecksumError:
        assert test_line.split()[1] in ["33333", "33334", "33335"]
        return

    for delay in times:
        try:
            test_time = delay.astype("timedelta64[m]") + o.tle.epoch
            pos, vel = o.get_position(test_time, False)
            res = get_results(
                int(o.tle.satnumber), float(delay))
        except NotImplementedError:
            # Skipping deep-space
            break
        # except ValueError, e:
        #     from warnings import warn
        #     warn(test_name + ' ' + str(e))
        #     break

        delta_pos = 5e-6  # km =  5 mm
        delta_vel = 5e-9  # km/s = 5 um/s
        delta_time = 1e-3  # 1 millisecond
        assert abs(res[0] - pos[0]) < delta_pos
        assert abs(res[1] - pos[1]) < delta_pos
        assert abs(res[2] - pos[2]) < delta_pos
        assert abs(res[3] - vel[0]) < delta_vel
        assert abs(res[4] - vel[1]) < delta_vel
        assert abs(res[5] - vel[2]) < delta_vel
        if res[6] is not None:
            dt = astronomy._days(res[6] - test_time) * 24 * 60
            assert abs(dt) < delta_time
