package com.sonymusic

import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import org.mockito.Mockito

import static org.junit.jupiter.api.Assertions.*

class UtilsTest {

    @Nested
    class ValidateParamsTest {
        @Test
        void testWithValidParams() {
            def params = [param1: "value1", param2: "value2"]
            def validationRules = [param1: [
                required: true, type: String],
                param2: [required: true, type: String]
            ]

            def result = Utils.validateParams('testVar', params, validationRules)

            assertEquals(params, result)
        }

        @Test
        void testWithMissingRequiredParam() {
            def params = [param1: "value1"]
            def validationRules = [
                param1: [required: true, type: String],
                param2: [required: true, type: String]
            ]

            assertThrows(IllegalArgumentException.class, {
                Utils.validateParams('testVar', params, validationRules)
            })
        }

        @Test
        void testWithInvalidType() {
            def params = [param1: 123]
            def validationRules = [
                param1: [required: true, type: String]
            ]

            assertThrows(IllegalArgumentException.class, {
                Utils.validateParams('testVar', params, validationRules)
            })
        }

        @Test
        void testWithDefaultValueForOptionalParam() {
            def params = [param1: "value1"]
            def validationRules = [
                param1: [required: true, type: String],
                param2: [required: false, type: String, defaultValue: "default"]
            ]

            def result = Utils.validateParams('testVar', params, validationRules)

            assertEquals("default", result.param2)
        }

        @Test
        void testWithUnknownParams() {
            def params = [param1: "value1", param2: "value2", unknownParam: "value"]
            def validationRules = [
                param1: [required: true, type: String],
                param2: [required: true, type: String]
            ]

            assertThrows(IllegalArgumentException.class, {
                Utils.validateParams('testVar', params, validationRules)
            })
        }

        @Test
        void testWithInvalidParamRule() {
            def params = [param1: "value1"]

            def exception = assertThrows(IllegalArgumentException.class, {
                Utils.validateParams('testVar', params, [
                    param1: []
                ])
            })

            assertEquals("testVar: The parameter validation rule for: 'param1', does not specify a 'type'.", exception.getMessage())

            exception = assertThrows(IllegalArgumentException.class, {
                Utils.validateParams('testVar', params, [
                    param1: [type: Map, itemType: String]
                ])
            })

            assertEquals(
                "testVar: The parameter validation rule for: 'param1', defines a 'itemType', but the 'type' is not a List.",
                exception.getMessage()
            )
        }
    }

    @Nested
    class IsTypeValidTest {
        @Test
        void testWithValidType() {
            assertTrue(Utils.isTypeValid("value", String))
            assertTrue(Utils.isTypeValid(0, Integer))
            assertTrue(Utils.isTypeValid(false, Boolean))
            assertTrue(Utils.isTypeValid([1, 2, 3], List))
            assertTrue(Utils.isTypeValid(["1", "2", "3"], List))
            assertTrue(Utils.isTypeValid([:], Map))
        }

        @Test
        void testWithValidGroovyStringType() {
            assertTrue(Utils.isTypeValid("Hello ${'World'}", String))
        }

        @Test
        void testWithInvalidType() {
            assertFalse(Utils.isTypeValid("value", Integer))
            assertFalse(Utils.isTypeValid(0, String))
            assertFalse(Utils.isTypeValid(0, Boolean))
            assertFalse(Utils.isTypeValid("value", List))
            assertFalse(Utils.isTypeValid([], Map))
        }

        @Test
        void testWithValidItemType() {
            assertTrue(Utils.isTypeValid([1, 2, 3], List, Integer))
            assertTrue(Utils.isTypeValid(["1", "2", "3"], List, String))
        }

        @Test
        void testWithInvalidItemType() {
            assertFalse(Utils.isTypeValid([1, "2", 3], List, String))
            assertFalse(Utils.isTypeValid(["1", 2, "3"], List, Integer))
            assertFalse(Utils.isTypeValid("value", List, String))
        }
    }

    @Nested
    class StripTrailingSlashTest {
        @Test
        void testWithTrailingSlash() {
            assertEquals("path/to/directory", Utils.stripTrailingSlash("path/to/directory/"))
        }

        @Test
        void testWithoutTrailingSlash() {
            assertEquals("path/to/directory", Utils.stripTrailingSlash("path/to/directory"))
        }
    }

    @Nested
    class EnsureTrailingSlashTest {
        @Test
        void testWithTrailingSlash() {
            assertEquals("path/to/directory/", Utils.ensureTrailingSlash("path/to/directory/"))
        }

        @Test
        void testWithoutTrailingSlash() {
            assertEquals("path/to/directory/", Utils.ensureTrailingSlash("path/to/directory"))
        }
    }

    @Nested
    class StripPrefixTest {
        @Test
        void testWithPrefix() {
            assertEquals("to/directory", Utils.stripPrefix("path/to/directory", "path/"))
        }

        @Test
        void testWithoutPrefix() {
            assertEquals("path/to/directory", Utils.stripPrefix("path/to/directory", "other/"))
        }
    }
}
