"""Tests for the Golang time.Time timestamp implementation."""

import decimal
import struct
import unittest

from dfdatetime import golang_time


class GolangEpochTest(unittest.TestCase):
    """Test for the Golang time.Time epoch."""

    def testInitialize(self):
        """Tests the __init__ function."""
        golang_epoch = golang_time.GolangTimeEpoch()
        self.assertIsNotNone(golang_epoch)

    def testEpochDate(self):
        """Tests the Golang time.Time epoch properties."""
        golang_epoch = golang_time.GolangTimeEpoch()
        self.assertEqual(golang_epoch.year, 1)
        self.assertEqual(golang_epoch.month, 1)
        self.assertEqual(golang_epoch.day_of_month, 1)


class GolangTest(unittest.TestCase):
    """Tests for the Golang time.Time timestamp."""

    # pylint: disable=protected-access

    def testProperties(self):
        """Tests the Golang time.Time timestamp properties."""
        golang_timestamp = struct.pack(">Bqih", 1, 0, 0, -1)
        golang_time_object = golang_time.GolangTime(golang_timestamp=golang_timestamp)
        self.assertEqual(golang_time_object._number_of_seconds, 0)
        self.assertEqual(golang_time_object._nanoseconds, 0)
        self.assertEqual(golang_time_object.is_local_time, False)
        self.assertEqual(golang_time_object._time_zone_offset, 0)

        golang_timestamp = struct.pack(
            ">Bqih", 1, golang_time.GolangTime._GOLANG_TO_POSIX_BASE, 0, 60
        )
        golang_time_object = golang_time.GolangTime(golang_timestamp=golang_timestamp)
        self.assertEqual(
            golang_time_object._number_of_seconds,
            golang_time.GolangTime._GOLANG_TO_POSIX_BASE,
        )
        self.assertEqual(golang_time_object._nanoseconds, 0)
        self.assertEqual(golang_time_object.is_local_time, False)
        self.assertEqual(golang_time_object._time_zone_offset, 60)

        golang_timestamp = bytes.fromhex("010000000e7791f70000000000ffff")
        golang_time_object = golang_time.GolangTime(golang_timestamp=golang_timestamp)
        self.assertEqual(
            golang_time_object._number_of_seconds,
            golang_time.GolangTime._GOLANG_TO_POSIX_BASE,
        )
        self.assertEqual(golang_time_object._nanoseconds, 0)
        self.assertEqual(golang_time_object.is_local_time, False)
        self.assertEqual(golang_time_object._time_zone_offset, 0)

    def testGetNormalizedTimestamp(self):
        """Test the _GetNormalizedTimestamp function."""
        golang_timestamp = bytes.fromhex("010000000000000000000000000000")
        golang_time_object = golang_time.GolangTime(golang_timestamp=golang_timestamp)

        normalized_timestamp = golang_time_object._GetNormalizedTimestamp()
        self.assertIsNone(normalized_timestamp)

        golang_timestamp = struct.pack(">Bqih", 1, 63772480949, 711098348, 0)
        golang_time_object = golang_time.GolangTime(golang_timestamp=golang_timestamp)

        normalized_timestamp = golang_time_object._GetNormalizedTimestamp()
        self.assertEqual(normalized_timestamp, decimal.Decimal("1636884149.711098348"))

        golang_timestamp = struct.pack(">Bqih", 1, 63772480949, 711098348, 60)
        golang_time_object = golang_time.GolangTime(golang_timestamp=golang_timestamp)

        normalized_timestamp = golang_time_object._GetNormalizedTimestamp()
        self.assertEqual(normalized_timestamp, decimal.Decimal("1636880549.711098348"))

        golang_timestamp = struct.pack(">Bqih", 1, 63772480949, 711098348, 0)
        golang_time_object = golang_time.GolangTime(golang_timestamp=golang_timestamp)
        golang_time_object.time_zone_offset = 60

        normalized_timestamp = golang_time_object._GetNormalizedTimestamp()
        self.assertEqual(normalized_timestamp, decimal.Decimal("1636880549.711098348"))

        golang_timestamp = bytes.fromhex("010000000e7791f70000000000ffff")
        golang_time_object = golang_time.GolangTime(golang_timestamp=golang_timestamp)

        normalized_timestamp = golang_time_object._GetNormalizedTimestamp()
        self.assertEqual(normalized_timestamp, decimal.Decimal("0"))

        golang_timestamp = bytes.fromhex("010000000e7791f60000000000ffff")
        golang_time_object = golang_time.GolangTime(golang_timestamp=golang_timestamp)

        normalized_timestamp = golang_time_object._GetNormalizedTimestamp()
        self.assertIsNone(normalized_timestamp)

    def testGetNumberOfSeconds(self):
        """Test the _GetNumberOfSeconds function."""
        golang_time_object = golang_time.GolangTime()

        golang_timestamp = bytes.fromhex("010000000000000002000000030004")
        number_of_seconds, nanoseconds, time_zone_offset = (
            golang_time_object._GetNumberOfSeconds(golang_timestamp)
        )
        self.assertEqual(number_of_seconds, 2)
        self.assertEqual(nanoseconds, 3)
        self.assertEqual(time_zone_offset, 4)

        golang_timestamp = bytes.fromhex("02000000000000000500000006ffff08")
        number_of_seconds, nanoseconds, time_zone_offset = (
            golang_time_object._GetNumberOfSeconds(golang_timestamp)
        )
        self.assertEqual(number_of_seconds, 5)
        self.assertEqual(nanoseconds, 6)
        self.assertEqual(time_zone_offset, 0)

        with self.assertRaises(ValueError):
            golang_timestamp = bytes.fromhex("0100")
            golang_time_object._GetNumberOfSeconds(golang_timestamp)

        with self.assertRaises(ValueError):
            golang_timestamp = bytes.fromhex("020000000000000000000000000000")
            golang_time_object._GetNumberOfSeconds(golang_timestamp)

        with self.assertRaises(ValueError):
            golang_timestamp = bytes.fromhex("ff0000000000000000000000000000")
            golang_time_object._GetNumberOfSeconds(golang_timestamp)

        with self.assertRaises(ValueError):
            golang_timestamp = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
            golang_time_object._GetNumberOfSeconds(golang_timestamp)

    def testCopyFromDateTimeString(self):
        """Tests the CopyFromDateTimeString function."""
        golang_time_object = golang_time.GolangTime()

        golang_time_object.CopyFromDateTimeString("0001-01-01")
        self.assertEqual(golang_time_object._number_of_seconds, 0)
        self.assertEqual(golang_time_object._nanoseconds, 0)
        self.assertEqual(golang_time_object._time_zone_offset, None)

        golang_time_object.CopyFromDateTimeString("0001-01-01 00:01:00")
        self.assertEqual(golang_time_object._number_of_seconds, 60)
        self.assertEqual(golang_time_object._nanoseconds, 0)
        self.assertEqual(golang_time_object._time_zone_offset, None)

        golang_time_object.CopyFromDateTimeString("0001-01-01 00:00:00.000001")
        self.assertEqual(golang_time_object._number_of_seconds, 0)
        self.assertEqual(golang_time_object._nanoseconds, 1000)
        self.assertEqual(golang_time_object._time_zone_offset, None)

        golang_time_object.CopyFromDateTimeString("2000-01-01")
        self.assertEqual(golang_time_object._number_of_seconds, 63082281600)
        self.assertEqual(golang_time_object._nanoseconds, 0)
        self.assertEqual(golang_time_object._time_zone_offset, None)

        golang_time_object.CopyFromDateTimeString("2000-01-01 12:23:45.567890")
        self.assertEqual(golang_time_object._number_of_seconds, 63082326225)
        self.assertEqual(golang_time_object._nanoseconds, 567890000)
        self.assertEqual(golang_time_object._time_zone_offset, None)

        golang_time_object.CopyFromDateTimeString("2000-01-01 12:23:45.567890+01:00")
        self.assertEqual(golang_time_object._number_of_seconds, 63082326225)
        self.assertEqual(golang_time_object._nanoseconds, 567890000)
        self.assertEqual(golang_time_object._time_zone_offset, 60)

        # Test with invalid date string.
        with self.assertRaises(ValueError):
            golang_time_object.CopyFromDateTimeString("0001:01-01 00:01:00")

        # Test with negative year.
        with self.assertRaises(ValueError):
            golang_time_object.CopyFromDateTimeString("-001-01-01 00:01:00")

    def testCopyToDateTimeString(self):
        """Test the CopyToDateTimeString function."""
        golang_timestamp = bytes.fromhex("010000000eafffe8d121d95050ffff")
        golang_time_object = golang_time.GolangTime(golang_timestamp=golang_timestamp)

        self.assertEqual(golang_time_object._number_of_seconds, 63082326225)
        self.assertEqual(golang_time_object._nanoseconds, 567890000)
        self.assertEqual(golang_time_object._time_zone_offset, 0)

        date_time_string = golang_time_object.CopyToDateTimeString()
        self.assertEqual(date_time_string, "2000-01-01 12:23:45.567890000")

        golang_timestamp = bytes.fromhex("010000000eafffe8d10000ddd5ffff")
        golang_time_object = golang_time.GolangTime(golang_timestamp=golang_timestamp)

        self.assertEqual(golang_time_object._number_of_seconds, 63082326225)
        self.assertEqual(golang_time_object._nanoseconds, 56789)
        self.assertEqual(golang_time_object._time_zone_offset, 0)

        date_time_string = golang_time_object.CopyToDateTimeString()
        self.assertEqual(date_time_string, "2000-01-01 12:23:45.000056789")

        golang_time_object = golang_time.GolangTime()
        date_time_string = golang_time_object.CopyToDateTimeString()
        self.assertIsNone(date_time_string)

    def testCopyToSerializableDict(self):
        """Test the CopyToSerializableDict function."""
        golang_timestamp = bytes.fromhex("010000000eafffe8d121d95050ffff")
        golang_time_object = golang_time.GolangTime(golang_timestamp=golang_timestamp)

        expected_serializable_dict = {
            "__class_name__": "GolangTime",
            "__type__": "DateTimeValues",
            "golang_timestamp": (
                b"\x01\x00\x00\x00\x0e\xaf\xff\xe8\xd1\x21\xd9\x50\x50\xff\xff"
            ),
        }
        serializable_dict = golang_time_object.CopyToSerializableDict()
        self.assertEqual(serializable_dict, expected_serializable_dict)


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