package com.sonymusic

import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test

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

class NodeShTest extends BaseGlobalVarTest {
    def nodeSh
    def workspaceDir = 'var/app/workspace'

    @BeforeEach
    void setUp() {
        super.setUp()
        nodeSh = loadScript('vars/nodeSh.groovy')

        helper.registerAllowedMethod('readFile', [String])
        helper.registerAllowedMethod('dockerRun', [Map])
        helper.registerAllowedMethod('withCredentials', [Map, Closure])
        helper.registerAllowedMethod('sh', [String])
        helper.registerAllowedMethod('pwd', [], { workspaceDir })
        helper.registerAllowedMethod('fileExists', [String], { args ->
            return args == './node_modules' ? true : false
        })

        binding.setVariable('env', [WORKSPACE: workspaceDir])
    }

    @Test
    void testCallWithNoArgs() {
        assertThrowsWithMessage(
            IllegalArgumentException.class, 
            "nodeSh: Missing required parameter: 'script'", 
            { nodeSh.call() }
        )
    }

    @Test
    void testCallWithUnsupportedNodeVersion() {
        assertThrowsWithMessage(
            IllegalArgumentException.class,
            "nodeSh: The node version '20.0.0' is not supported. Supported versions: [18,20.11.1,20,20-build,22,24]",
            { nodeSh.call(script: 'test', nodeVersion: '20.0.0') }
        )
    }

    @Test
    void testCallWithNoNmvrcFile() {
        helper.registerAllowedMethod('fileExists', [String], { return false })

        assertThrowsWithMessage(
            AssertionError.class,
            'nodeSh: The "nodeVersion" parameter is required when there is no .nvmrc file in the repo', 
            { nodeSh.call(script: 'echo hi') }
        )
    }

    @Test
    void testCallWithNoNodeModulesFolder() {
        helper.registerAllowedMethod('fileExists', [String], { args ->
            return args == './node_modules' ? false : true
        })

        assertNull(
            nodeSh(script: 'echo hi', nodeVersion: '20.11.1')
        )

        assertMethodCalledOnceWith("sh", 'chmod -R -f a=rwx ./')
        assertMethodCalledTimes('withCredentials', 1)
        assertMethodCalledTimes('dockerRun', 1)
    }

    @Test
    void testCallWithNodeModulesFolder() {
        helper.registerAllowedMethod('fileExists', [String], { args ->
            return args == './node_modules' ? true : false
        })
        
        assertNull(
            nodeSh(script: 'echo hi', nodeVersion: '20.11.1')
        )

        assertMethodCalledTimes('sh', 0)
        assertMethodCalledTimes('withCredentials', 1)
        assertMethodCalledTimes('dockerRun', 1)
    }

    @Test
    void testCallWithScript() {
        assertNull(
            nodeSh(script: 'echo hi', nodeVersion: '20.11.1')
        )

        assertMethodCalledTimes('sh', 0)
        assertMethodCalledOnceWith('withCredentials', "[GITHUB_NPM_TOKEN]")
        assertMethodCalledOnceWith('dockerRun', [
            'imageTag=node20.11.1',
            'user=node',
            'workdir=/var/app',
            'volumes=[$(pwd):/var/app]',
            'envVars={GITHUB_NPM_TOKEN=${GITHUB_NPM_TOKEN}}',
            'script=echo hi'
        ])
    }

    @Test
    void testCallWithNode18() {
        assertNull(
            nodeSh(script: 'echo hi', nodeVersion: '18')
        )

        assertMethodCalledTimes('sh', 0)
        assertMethodCalledOnceWith('withCredentials', "[GITHUB_NPM_TOKEN]")
        assertMethodCalledOnceWith('dockerRun', [
            'imageTag=node18',
            'user=node',
            'workdir=/var/app',
            'volumes=[$(pwd):/var/app]',
            'envVars={GITHUB_NPM_TOKEN=${GITHUB_NPM_TOKEN}}',
            'script=echo hi'
        ])
    }

    @Test
    void testCallWithNodeLtsHydrogen() {
        assertNull(
            nodeSh(script: 'echo hi', nodeVersion: 'lts/hydrogen')
        )

        assertMethodCalledTimes('sh', 0)
        assertMethodCalledOnceWith('withCredentials', "[GITHUB_NPM_TOKEN]")
        assertMethodCalledOnceWith('dockerRun', [
            'imageTag=node18',
            'user=node',
            'workdir=/var/app',
            'volumes=[$(pwd):/var/app]',
            'envVars={GITHUB_NPM_TOKEN=${GITHUB_NPM_TOKEN}}',
            'script=echo hi'
        ])
    }

    @Test
    void testCallWithNode20() {
        assertNull(
            nodeSh(script: 'echo hi', nodeVersion: '20')
        )

        assertMethodCalledTimes('sh', 0)
        assertMethodCalledOnceWith('withCredentials', "[GITHUB_NPM_TOKEN]")
        assertMethodCalledOnceWith('dockerRun', [
            'imageTag=node20',
            'user=node',
            'workdir=/var/app',
            'volumes=[$(pwd):/var/app]',
            'envVars={GITHUB_NPM_TOKEN=${GITHUB_NPM_TOKEN}}',
            'script=echo hi'
        ])
    }

    @Test
    void testCallWithNode20x() {
        assertNull(
            nodeSh(script: 'echo hi', nodeVersion: '20.x')
        )

        assertMethodCalledTimes('sh', 0)
        assertMethodCalledOnceWith('withCredentials', "[GITHUB_NPM_TOKEN]")
        assertMethodCalledOnceWith('dockerRun', [
            'imageTag=node20',
            'user=node',
            'workdir=/var/app',
            'volumes=[$(pwd):/var/app]',
            'envVars={GITHUB_NPM_TOKEN=${GITHUB_NPM_TOKEN}}',
            'script=echo hi'
        ])
    }


    @Test
    void testCallWithNode20Build() {
        assertNull(
            nodeSh(script: 'echo hi', nodeVersion: '20-build')
        )

        assertMethodCalledTimes('sh', 0)
        assertMethodCalledOnceWith('withCredentials', "[GITHUB_NPM_TOKEN]")
        assertMethodCalledOnceWith('dockerRun', [
            'imageTag=node20-build',
            'user=node',
            'workdir=/var/app',
            'volumes=[$(pwd):/var/app]',
            'envVars={GITHUB_NPM_TOKEN=${GITHUB_NPM_TOKEN}}',
            'script=echo hi'
        ])
    }

    @Test
    void testCallWithNode22() {
        assertNull(
            nodeSh(script: 'echo hi', nodeVersion: '22')
        )

        assertMethodCalledTimes('sh', 0)
        assertMethodCalledOnceWith('withCredentials', "[GITHUB_NPM_TOKEN]")
        assertMethodCalledOnceWith('dockerRun', [
            'imageTag=node22',
            'user=node',
            'workdir=/var/app',
            'volumes=[$(pwd):/var/app]',
            'envVars={GITHUB_NPM_TOKEN=${GITHUB_NPM_TOKEN}}',
            'script=echo hi'
        ])
    }

    @Test
    void testCallWithNode24() {
        assertNull(
            nodeSh(script: 'echo hi', nodeVersion: '24')
        )

        assertMethodCalledTimes('sh', 0)
        assertMethodCalledOnceWith('withCredentials', "[GITHUB_NPM_TOKEN]")
        assertMethodCalledOnceWith('dockerRun', [
            'imageTag=node24',
            'user=node',
            'workdir=/var/app',
            'volumes=[$(pwd):/var/app]',
            'envVars={GITHUB_NPM_TOKEN=${GITHUB_NPM_TOKEN}}',
            'script=echo hi'
        ])
    }

    @Test
    void testCallWithNvmrcFile() {
        helper.registerAllowedMethod('fileExists', [String], { return true })
        helper.registerAllowedMethod('readFile', [String], { args ->
            return args == workspaceDir + '/.nvmrc' ? ' 20.11.1 \n' : 'na'
        })

        assertNull(
            nodeSh(script: 'echo hi')
        )

        assertMethodCalledTimes('sh', 0)
        assertMethodCalledTimes('withCredentials', 1)
        assertMethodCalledOnceWith('dockerRun', [
            'imageTag=node20.11.1',
            'user=node',
            'envVars={GITHUB_NPM_TOKEN=${GITHUB_NPM_TOKEN}}',
            'script=echo hi'
        ])
    }

    @Test
    void testCallWithRootNvmrcFile() {
        def rootNvmrcFile = workspaceDir + '/.nvmrc'

        helper.registerAllowedMethod('pwd', [], { 'var/app/workspace/sub/sub' })
        helper.registerAllowedMethod('fileExists', [String], { path ->
            return path == rootNvmrcFile
        })
        helper.registerAllowedMethod('readFile', [String], { path ->
            return path == rootNvmrcFile ? '20.11.1' : 'na'
        })

        assertNull(
            nodeSh(script: 'echo hi')
        )

        assertMethodCalledTimes('sh', 1)
        assertMethodCalledTimes('withCredentials', 1)
        assertMethodCalledOnceWith('dockerRun', [
            'imageTag=node20.11.1',
            'user=node',
            'envVars={GITHUB_NPM_TOKEN=${GITHUB_NPM_TOKEN}}',
            'script=echo hi'
        ])
    }

    @Test
    void testCallWithInvalidNvmrcFile() {
        def rootNvmrcFile = workspaceDir + '/.nvmrc'

        helper.registerAllowedMethod('fileExists', [String], { args ->
            return args ==  rootNvmrcFile
        })
        helper.registerAllowedMethod('readFile', [String], { args ->
            return args == rootNvmrcFile ? '20.0.0' : 'na'
        })

        assertThrowsWithMessage(
            IllegalArgumentException.class,
            "The node version '20.0.0' is not supported. Supported versions: [18,20.11.1,20,20-build,22,24]",
            { nodeSh.call(script: 'echo hi') }
        )
    }

    @Test
    void testCallWithEnvVars() {
        assertNull(
            nodeSh(
                script: 'echo hi', 
                nodeVersion: '20.11.1',
                envVars: [
                    TEST: 'value',
                    GITHUB_NPM_TOKEN: 'not possible to override'
                ]
            )
        )

        assertMethodCalledTimes('sh', 0)
        assertMethodCalledTimes('withCredentials', 1)
        assertMethodCalledOnceWith('dockerRun', [
            'imageTag=node20.11.',
            'user=node',
            'envVars={TEST=value, GITHUB_NPM_TOKEN=${GITHUB_NPM_TOKEN}}',
            'script=echo hi'
        ])
    }

    @Test
    void testCallWithString() {
        helper.registerAllowedMethod('fileExists', [String], { return true })
        helper.registerAllowedMethod('readFile', [String], { args ->
            return args == workspaceDir + '/.nvmrc' ? ' 20.11.1 \n' : 'na'
        })

        assertNull(
            nodeSh('echo hi')
        )

        assertMethodCalledTimes('sh', 0)
        assertMethodCalledTimes('withCredentials', 1)
        assertMethodCalledOnceWith('dockerRun', [
            'imageTag=node20.11.1',
            'user=node',
            'envVars={GITHUB_NPM_TOKEN=${GITHUB_NPM_TOKEN}}',
            'script=echo hi'
        ])
    }

    @Test
    void testCallWithUser() {
        assertNull(
            nodeSh(
                script: 'echo hi tim', 
                nodeVersion: '20.11.1',
                user: 'tim'
            )
        )

        assertMethodCalledTimes('sh', 0)
        assertMethodCalledTimes('withCredentials', 1)
        assertMethodCalledOnceWith('dockerRun', [
            'imageTag=node20.11.1',
            'user=tim',
            'script=echo hi tim'
        ])
    }
}
