import math
import unittest

from sohstationviewer.model.reftek.reftek import (
    two_digit_year_to_four_digit_year,
    RT130
)


class TestTwoDigitYearToFourDigitYear(unittest.TestCase):
    def test_2000_years(self):
        test_cases = {
            '0': '2000',
            '00': '2000',
            '1': '2001',
            '01': '2001',
            '12': '2012',
            '68': '2068',
        }
        for input, expected_output in test_cases.items():
            with self.subTest(f'test_input_{input}'):
                result = two_digit_year_to_four_digit_year(input)
                self.assertEqual(result, expected_output)

    def test_1900_years(self):
        test_cases = {
            '69': '1969',
            '99': '1999',
            '75': '1975',
        }
        for input, expected_output in test_cases.items():
            with self.subTest(f'test_input_{input}'):
                result = two_digit_year_to_four_digit_year(input)
                self.assertEqual(result, expected_output)

    def test_invalid_input(self):
        with self.subTest('test_negative_year'):
            input = '-1'
            with self.assertRaises(ValueError):
                two_digit_year_to_four_digit_year(input)
        with self.subTest('test_year_has_more_than_two_dgit'):
            input = '123'
            with self.assertRaises(ValueError):
                two_digit_year_to_four_digit_year(input)
        with self.subTest('test_non_sensical_input'):
            input = 'tt'
            with self.assertRaises(ValueError):
                two_digit_year_to_four_digit_year(input)


class TestParseGpsPoint(unittest.TestCase):
    def setUp(self) -> None:
        self.gps_year = '2000'
        self.good_gps_line = ('150:03:00:00 GPS: POSITION: N34:04:26.94 '
                              'E106:55:13.39 +01425M')

    def test_not_enough_gps_field(self):
        gps_line = '150:03:00:00 GPS: POSITION: N34:04:26.94 W106:55:13.39'
        with self.assertRaises(IndexError):
            RT130.parse_gps_point(gps_line, self.gps_year)

    def test_time_formatted_correctly(self):
        gps_point = RT130.parse_gps_point(self.good_gps_line, self.gps_year)
        result = gps_point.last_timemark
        expected = '2000-05-29 03:00:00'
        self.assertEqual(result, expected)

    def test_latitude_extracted_correctly(self):
        with self.subTest('test_northern_latitude'):
            gps_point = RT130.parse_gps_point(self.good_gps_line,
                                              self.gps_year)
            result = gps_point.latitude
            expected = 34.07415
            self.assertTrue(math.isclose(result, expected))

        with self.subTest('test_southern_latitude'):
            self.good_gps_line = (self.good_gps_line[:28] +
                                  'S' +
                                  self.good_gps_line[29:])
            gps_point = RT130.parse_gps_point(self.good_gps_line,
                                              self.gps_year)
            result = gps_point.latitude
            expected = -34.07415
            self.assertTrue(math.isclose(result, expected))

    def test_longitude_extracted_correctly(self):
        with self.subTest('test_eastern_longitude'):
            gps_point = RT130.parse_gps_point(self.good_gps_line,
                                              self.gps_year)
            result = gps_point.longitude
            expected = 106.92038611111111
            self.assertTrue(math.isclose(result, expected))

        with self.subTest('test_western_longitude'):
            self.good_gps_line = (self.good_gps_line[:41] +
                                  'W' +
                                  self.good_gps_line[42:])
            gps_point = RT130.parse_gps_point(self.good_gps_line,
                                              self.gps_year)
            result = gps_point.longitude
            print(result)
            expected = -106.92038611111111
            self.assertTrue(math.isclose(result, expected))

    def test_height_extracted_correctly(self):
        with self.subTest('test_positive_height'):
            gps_point = RT130.parse_gps_point(self.good_gps_line,
                                              self.gps_year)
            result = gps_point.height
            expected = 1425
            self.assertTrue(math.isclose(result, expected))

        with self.subTest('test_negative_height'):
            self.good_gps_line = self.good_gps_line.replace('+', '-')
            gps_point = RT130.parse_gps_point(self.good_gps_line,
                                              self.gps_year)
            result = gps_point.height
            expected = -1425
            self.assertTrue(math.isclose(result, expected))

    def test_height_unit_extracted_correctly(self):
        with self.subTest('test_one_character_height_unit'):
            gps_point = RT130.parse_gps_point(self.good_gps_line,
                                              self.gps_year)
            result = gps_point.height_unit
            expected = 'M'
            self.assertEqual(result, expected)

        with self.subTest('test_more_than_one_character_height_unit'):
            self.good_gps_line = self.good_gps_line + 'MM'
            gps_point = RT130.parse_gps_point(self.good_gps_line,
                                              self.gps_year)
            result = gps_point.height_unit
            expected = 'MMM'
            self.assertEqual(result, expected)