#!/usr/bin/env python3
# Copyright: 2026, Maximiliano Curia <maxy@debian.org>
#
# License: ISC
#  Permission to use, copy, modify, and/or distribute this software for any
#  purpose with or without fee is hereby granted, provided that the above
#  copyright notice and this permission notice appear in all copies.
#  .
#  THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
#  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
#  AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
#  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
#  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
#  OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
#  PERFORMANCE OF THIS SOFTWARE.

"""Tests for YearRange class extraction to core_types.py"""

import unittest

try:
    from decopy.core_types import YearRange
except ImportError as e:
    msg = "Cannot import YearRange from core_types module"
    raise ImportError(msg) from e


class TestYearRangeClass(unittest.TestCase):
    """Test YearRange class functionality in core_types module"""

    def setUp(self):
        """Set up test fixtures"""

    def test_year_range_single_year_creation(self):
        """Test YearRange creation with single year"""
        year_range = YearRange(2020)
        self.assertIsNotNone(year_range)
        self.assertEqual(year_range.low, 2020)
        self.assertEqual(year_range.high, 2020)
        self.assertEqual(year_range.low, year_range.high)
        self.assertIsInstance(year_range, YearRange)

    def test_year_range_range_creation(self):
        """Test YearRange creation with year range"""
        year_range = YearRange(2020, 2023)
        self.assertIsNotNone(year_range)
        self.assertEqual(year_range.low, 2020)
        self.assertEqual(year_range.high, 2023)
        self.assertTrue(year_range.low < year_range.high)
        self.assertIsInstance(year_range, YearRange)

    def test_year_range_string_representation(self):
        """Test YearRange string representation"""
        # Single year
        single = YearRange(2020)
        self.assertEqual(str(single), "2020")

        # Year range
        range_ = YearRange(2020, 2023)
        self.assertEqual(str(range_), "2020-2023")

        # Single year created as range
        same = YearRange(2020, 2020)
        self.assertEqual(str(same), "2020")

    def test_year_range_contains_method(self):
        """Test YearRange __contains__ method for year containment"""
        year_range = YearRange(2020, 2023)

        # Years within range (using proper __contains__ method)
        self.assertTrue(2020 in year_range)  # Start year  # noqa: PLR2004
        self.assertTrue(2021 in year_range)  # Middle year # noqa: PLR2004
        self.assertTrue(2022 in year_range)  # Middle year # noqa: PLR2004
        self.assertTrue(2023 in year_range)  # End year    # noqa: PLR2004

        # Years outside range
        self.assertFalse(2019 in year_range)  # Before range # noqa: PLR2004
        self.assertFalse(2024 in year_range)  # After range  # noqa: PLR2004

    def test_year_range_add_method(self):
        """Test YearRange add method"""
        # Start with base range
        base = YearRange(2020, 2023)

        # Add year within current range (should not change)
        result1 = base.add(2021)
        self.assertEqual(result1.low, 2020)
        self.assertEqual(result1.high, 2023)

        # Add year before current range (create new instance)
        result2 = base.add(2019)
        self.assertEqual(result2.low, 2019)
        self.assertEqual(result2.high, 2023)

        # Add year after current range (create new instance)
        result3 = base.add(2025)
        self.assertEqual(result3.low, 2019)  # Accumulated from previous add
        self.assertEqual(result3.high, 2025)

    def test_year_range_merge_method(self):
        """Test YearRange merge method"""
        year_range1 = YearRange(2020, 2023)
        year_range2 = YearRange(2022, 2025)

        # Merge overlapping ranges
        merged = year_range1.merge(year_range2)
        self.assertEqual(merged.low, 2020)
        self.assertEqual(merged.high, 2025)

    def test_year_range_newer_method(self):
        """Test YearRange newer method"""
        # More recent range (higher end year)
        recent = YearRange(2020, 2023)
        older = YearRange(2018, 2021)

        # The method checks if 'other' is newer than 'self'
        # So recent.newer(older) means 'is older newer than recent?' -> False
        # And older.newer(recent) means 'is recent newer than older?' -> True
        self.assertFalse(recent.newer(older), "Older is not newer than recent")
        self.assertTrue(older.newer(recent), "Recent is newer than older")

        # Test with same end year but different start years
        recent2 = YearRange(2019, 2023)
        older2 = YearRange(2018, 2022)

        self.assertFalse(recent2.newer(older2), "Older2 is not newer than recent2")
        self.assertTrue(older2.newer(recent2), "Recent2 is newer than older2")

    def test_year_range_boolean_value(self):
        """Test YearRange boolean evaluation"""
        # Non-empty range
        year_range = YearRange(2020, 2023)
        self.assertTrue(year_range, "Non-empty range should be True")

        # Empty range (should be created with no years)
        empty = YearRange()
        self.assertFalse(empty, "Empty range should be False")

    def test_year_range_with_string_input(self):
        """Test YearRange creation with string input"""
        year_range = YearRange("2020", "2023")
        self.assertEqual(year_range.low, 2020)
        self.assertEqual(year_range.high, 2023)

        # Test with single string
        single = YearRange("2020")
        self.assertEqual(single.low, 2020)
        self.assertEqual(single.high, 2020)

    def test_year_range_with_none_input(self):
        """Test YearRange creation with None input"""
        # Low is None, high is None
        year_range = YearRange(None, None)
        self.assertEqual(year_range.low, 0)  # Default value
        self.assertEqual(year_range.high, 0)

        # Low is None, high has value
        year_range2 = YearRange(None, 2023)
        self.assertEqual(year_range2.low, 0)
        self.assertEqual(year_range2.high, 2023)

    def test_year_range_automatic_range_ordering(self):
        """Test that YearRange automatically orders low and high"""
        # Create with high < low, should auto-correct
        year_range = YearRange(2023, 2020)
        self.assertEqual(year_range.low, 2020)
        self.assertEqual(year_range.high, 2023)

    def test_multiple_year_range_instances(self):
        """Test creating multiple YearRange instances"""
        ranges = [
            YearRange(2020, 2023),
            YearRange(2018, 2021),
            YearRange(2022, 2025),
            YearRange(2019),
        ]

        # All should be different instances
        self.assertEqual(len(ranges), 4)

        # Test they maintain correct values
        self.assertEqual(ranges[0].low, 2020)
        self.assertEqual(ranges[0].high, 2023)
        self.assertEqual(ranges[1].low, 2018)
        self.assertEqual(ranges[1].high, 2021)
        self.assertEqual(ranges[2].low, 2022)
        self.assertEqual(ranges[2].high, 2025)
        self.assertEqual(ranges[3].low, 2019)
        self.assertEqual(ranges[3].high, 2019)


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