import unittest
import math

from sohstationviewer.model.mseed.mseed import MSeed


class TestCheckGPSStatusFormatQ330(unittest.TestCase):
    def setUp(self) -> None:
        self.status_lines = [
            'GPS Status',
            'Time: 18:28:49',
            'Date: 27/08/2018',
            'Fix Type: 3-D',
            'Height: 47.6M',
            'Latitude: 5906.7572N',
            'Longitude: 15651.4038W',
            'On Time: 15min',
            'Sat. Used: 6',
            'In View: 11',
            'Checksum Errors: 0',
            'Last GPS timemark: 2018-08-27 18:28:48',
            'PLL Status'
        ]

    def test_not_enough_status_lines(self):
        self.status_lines.pop()
        with self.assertRaises(ValueError):
            MSeed.check_gps_status_format_q330(self.status_lines)

    def test_too_many_status_lines(self):
        self.status_lines.append('')
        with self.assertRaises(ValueError):
            MSeed.check_gps_status_format_q330(self.status_lines)

    def test_gps_status_not_followed_by_pll_status(self):
        self.status_lines[12] = ''
        with self.assertRaises(ValueError):
            MSeed.check_gps_status_format_q330(self.status_lines)

    def test_good_data(self):
        try:
            MSeed.check_gps_status_format_q330(self.status_lines)
        except ValueError:
            self.fail()

    def test_fix_type_bad_data(self):
        self.status_lines[3] = ''
        with self.assertRaises(ValueError):
            MSeed.check_gps_status_format_q330(self.status_lines)

    def test_height_bad_data(self):
        self.status_lines[4] = ''
        with self.assertRaises(ValueError):
            MSeed.check_gps_status_format_q330(self.status_lines)

    def test_latitude_bad_data(self):
        self.status_lines[5] = ''
        with self.assertRaises(ValueError):
            MSeed.check_gps_status_format_q330(self.status_lines)

    def test_longitude_bad_data(self):
        self.status_lines[6] = ''
        with self.assertRaises(ValueError):
            MSeed.check_gps_status_format_q330(self.status_lines)

    def test_sat_used_bad_data(self):
        self.status_lines[8] = ''
        with self.assertRaises(ValueError):
            MSeed.check_gps_status_format_q330(self.status_lines)

    def test_gps_timemark_bad_data(self):
        self.status_lines[11] = ''
        with self.assertRaises(ValueError):
            MSeed.check_gps_status_format_q330(self.status_lines)


class TestExtractGPSPointQ330(unittest.TestCase):
    def setUp(self) -> None:
        self.gps_lines = ['GPS Status',
                          'Time: 03:37:39',
                          'Date: 05/07/2021',
                          'Fix Type: 3-D',
                          'Height: 1000.6M',
                          'Latitude: 3853.9013N',
                          'Longitude: 04610.8865E',
                          'On Time: 65535min',
                          'Sat. Used: 7',
                          'In View: 11',
                          'Checksum Errors: 0',
                          'Last GPS timemark: 2021-07-05 03:37:38']

    def test_not_enough_gps_lines(self):
        self.gps_lines.pop()
        with self.assertRaises(ValueError):
            MSeed.extract_gps_point_q330(self.gps_lines)

    def test_too_many_gps_lines(self):
        self.gps_lines.append('')
        with self.assertRaises(ValueError):
            MSeed.extract_gps_point_q330(self.gps_lines)

    def test_last_timemark_extracted_correctly(self):
        with self.subTest('test_data_from_file'):
            result = MSeed.extract_gps_point_q330(self.gps_lines)
            expected = '2021-07-05 03:37:38'
            self.assertEqual(result.last_timemark, expected)

        with self.subTest('test_made_up_data'):
            self.gps_lines[11] = 'Last GPS timemark: test time mark'
            result = MSeed.extract_gps_point_q330(self.gps_lines)
            expected = 'test time mark'
            self.assertEqual(result.last_timemark, expected)

    def test_fix_type_extracted_correctly(self):
        with self.subTest('test_data_from_file'):
            result = MSeed.extract_gps_point_q330(self.gps_lines)
            expected = '3-D'
            self.assertEqual(result.fix_type, expected)

        with self.subTest('test_made_up_data'):
            self.gps_lines[3] = 'Fix Type: test fix type'
            result = MSeed.extract_gps_point_q330(self.gps_lines)
            expected = 'test fix type'
            self.assertEqual(result.fix_type, expected)

    def test_height_extracted_correctly(self):
        with self.subTest('test_data_from_file'):
            result = MSeed.extract_gps_point_q330(self.gps_lines)
            expected = 1000.6
            self.assertTrue(math.isclose(result.height, expected))

        with self.subTest('test_made_up_data'):
            self.gps_lines[4] = 'Height: 3522362.623623MMMSM'
            result = MSeed.extract_gps_point_q330(self.gps_lines)
            expected = 3522362.623623
            self.assertTrue(math.isclose(result.height, expected))

    def test_height_unit_extracted_correctly(self):
        with self.subTest('test_data_from_file'):
            result = MSeed.extract_gps_point_q330(self.gps_lines)
            expected = 'M'
            self.assertEqual(result.height_unit, expected)

        with self.subTest('test_made_up_data'):
            self.gps_lines[4] = 'Height: 3522362.623623MMMSM'
            result = MSeed.extract_gps_point_q330(self.gps_lines)
            expected = 'MMMSM'
            self.assertEqual(result.height_unit, expected)

    def test_latitude_extracted_correctly(self):
        with self.subTest('test_latitude_in_the_north'):
            result = MSeed.extract_gps_point_q330(self.gps_lines)
            expected = 38.898355
            self.assertTrue(math.isclose(result.latitude, expected))

        with self.subTest('test_latitude_in_the_south'):
            self.gps_lines[5] = 'Latitude: 3853.9013S'
            result = MSeed.extract_gps_point_q330(self.gps_lines)
            expected = -38.898355
            self.assertTrue(math.isclose(result.latitude, expected))

    def test_longitude_extracted_correctly(self):
        with self.subTest('test_longitude_in_the_east'):
            result = MSeed.extract_gps_point_q330(self.gps_lines)
            expected = 46.18144166666666667
            self.assertTrue(math.isclose(result.longitude, expected))

        with self.subTest('test_longitude_in_the_west'):
            self.gps_lines[6] = 'Longitude: 04610.8865W'
            result = MSeed.extract_gps_point_q330(self.gps_lines)
            expected = -46.18144166666666667
            self.assertTrue(math.isclose(result.longitude, expected))

    def test_num_sat_used_extracted_correctly(self):
        with self.subTest('test_longitude_in_the_east'):
            result = MSeed.extract_gps_point_q330(self.gps_lines)
            expected = 7
            self.assertEqual(result.num_satellite_used, expected)

        with self.subTest('test_longitude_in_the_west'):
            self.gps_lines[8] = 'Sat. Used: 53252352'
            result = MSeed.extract_gps_point_q330(self.gps_lines)
            expected = 53252352
            self.assertEqual(result.num_satellite_used, expected)

    def test_no_location_data(self):
        self.gps_lines[4] = 'Height: '
        self.gps_lines[5] = 'Latitude: '
        self.gps_lines[6] = 'Longitude: '
        self.gps_lines[8] = 'Sat. Used: '
        result = MSeed.extract_gps_point_q330(self.gps_lines)
        self.assertEqual(result.last_timemark, '2021-07-05 03:37:38')
        self.assertEqual(result.fix_type, '3-D')
        self.assertEqual(result.height, 0)
        self.assertEqual(result.latitude, 0)
        self.assertEqual(result.longitude, 0)
        self.assertEqual(result.num_satellite_used, 0)