from orionis.foundation.config.logging.entities.channels import Channels
from orionis.foundation.config.logging.entities.stack import Stack
from orionis.foundation.config.logging.entities.hourly import Hourly
from orionis.foundation.config.logging.entities.daily import Daily
from orionis.foundation.config.logging.entities.weekly import Weekly
from orionis.foundation.config.logging.entities.monthly import Monthly
from orionis.foundation.config.logging.entities.chunked import Chunked
from orionis.foundation.config.exceptions.integrity import OrionisIntegrityException
from orionis.unittesting import TestCase

class TestConfigChannels(TestCase):
    """
    Test cases for the Channels logging configuration class.
    """

    async def testDefaultValues(self):
        """
        Test that Channels instance is created with correct default values.
        Verifies all channel configurations are properly initialized with their default values.
        """
        channels = Channels()
        self.assertIsInstance(channels.stack, Stack)
        self.assertIsInstance(channels.hourly, Hourly)
        self.assertIsInstance(channels.daily, Daily)
        self.assertIsInstance(channels.weekly, Weekly)
        self.assertIsInstance(channels.monthly, Monthly)
        self.assertIsInstance(channels.chunked, Chunked)

    async def testStackValidation(self):
        """
        Test stack attribute type validation.
        Verifies that only Stack instances are accepted for stack attribute.
        """
        with self.assertRaises(OrionisIntegrityException):
            Channels(stack="not_a_stack_instance")
        with self.assertRaises(OrionisIntegrityException):
            Channels(stack=123)
        try:
            Channels(stack=Stack())
        except OrionisIntegrityException:
            self.fail("Valid Stack instance should not raise exception")

    async def testHourlyValidation(self):
        """
        Test hourly attribute type validation.
        """
        with self.assertRaises(OrionisIntegrityException):
            Channels(hourly="not_an_hourly_instance")
        try:
            Channels(hourly=Hourly())
        except OrionisIntegrityException:
            self.fail("Valid Hourly instance should not raise exception")

    async def testDailyValidation(self):
        """
        Test daily attribute type validation.
        """
        with self.assertRaises(OrionisIntegrityException):
            Channels(daily="not_a_daily_instance")
        try:
            Channels(daily=Daily())
        except OrionisIntegrityException:
            self.fail("Valid Daily instance should not raise exception")

    async def testWeeklyValidation(self):
        """
        Test weekly attribute type validation.
        """
        with self.assertRaises(OrionisIntegrityException):
            Channels(weekly="not_a_weekly_instance")
        try:
            Channels(weekly=Weekly())
        except OrionisIntegrityException:
            self.fail("Valid Weekly instance should not raise exception")

    async def testMonthlyValidation(self):
        """
        Test monthly attribute type validation.
        """
        with self.assertRaises(OrionisIntegrityException):
            Channels(monthly="not_a_monthly_instance")
        try:
            Channels(monthly=Monthly())
        except OrionisIntegrityException:
            self.fail("Valid Monthly instance should not raise exception")

    async def testChunkedValidation(self):
        """
        Test chunked attribute type validation.
        """
        with self.assertRaises(OrionisIntegrityException):
            Channels(chunked="not_a_chunked_instance")
        try:
            Channels(chunked=Chunked())
        except OrionisIntegrityException:
            self.fail("Valid Chunked instance should not raise exception")

    async def testCustomConfigurations(self):
        """
        Test that custom channel configurations are properly stored and validated.
        """
        custom_stack = Stack(path="custom/stack.log")
        custom_hourly = Hourly(path="custom/hourly.log")
        custom_daily = Daily(path="custom/daily.log")
        custom_weekly = Weekly(path="custom/weekly.log")
        custom_monthly = Monthly(path="custom/monthly.log")
        custom_chunked = Chunked(path="custom/chunked.log")

        channels = Channels(
            stack=custom_stack,
            hourly=custom_hourly,
            daily=custom_daily,
            weekly=custom_weekly,
            monthly=custom_monthly,
            chunked=custom_chunked
        )
        self.assertEqual(channels.stack.path, "custom/stack.log")
        self.assertEqual(channels.hourly.path, "custom/hourly.log")
        self.assertEqual(channels.daily.path, "custom/daily.log")
        self.assertEqual(channels.weekly.path, "custom/weekly.log")
        self.assertEqual(channels.monthly.path, "custom/monthly.log")
        self.assertEqual(channels.chunked.path, "custom/chunked.log")

    async def testToDictMethod(self):
        """
        Test that toDict returns proper dictionary representation.
        """
        channels = Channels()
        channels_dict = channels.toDict()
        self.assertIsInstance(channels_dict, dict)
        self.assertIsInstance(channels_dict['stack'], dict)
        self.assertIsInstance(channels_dict['hourly'], dict)
        self.assertIsInstance(channels_dict['daily'], dict)
        self.assertIsInstance(channels_dict['weekly'], dict)
        self.assertIsInstance(channels_dict['monthly'], dict)
        self.assertIsInstance(channels_dict['chunked'], dict)

    async def testHashability(self):
        """
        Test that Channels maintains hashability due to unsafe_hash=True.
        """
        channels1 = Channels()
        channels2 = Channels()
        channels_set = {channels1, channels2}

        self.assertEqual(len(channels_set), 1)

        custom_channels = Channels(stack=Stack(path="custom.log"))
        channels_set.add(custom_channels)
        self.assertEqual(len(channels_set), 2)

    async def testKwOnlyInitialization(self):
        """
        Test that Channels enforces keyword-only initialization.
        """
        with self.assertRaises(TypeError):
            Channels(Stack(), Hourly(), Daily(), Weekly(), Monthly(), Chunked())