/*
 * Copyright 2013-2026, Seqera Labs
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package nextflow.extension

import java.util.concurrent.TimeUnit

import groovyx.gpars.dataflow.DataflowBroadcast
import groovyx.gpars.dataflow.DataflowQueue
import groovyx.gpars.dataflow.DataflowVariable
import nextflow.Channel
import spock.lang.Specification

import static test.ScriptHelper.runDataflow
/**
 *
 * @author Paolo Di Tommaso <paolo.ditommaso@gmail.com>
 */
class CHTest extends Specification {

    def 'should create dataflow variable or queue' () {

        expect:
        CH.create() instanceof DataflowBroadcast
        CH.create(false) instanceof DataflowBroadcast
        CH.create(true) instanceof DataflowVariable

        CH.createBy(new DataflowVariable()) instanceof DataflowVariable
        CH.createBy(new DataflowQueue()) instanceof DataflowBroadcast
    }

    def 'should check queue channel' () {
        expect:
        CH.isChannelQueue(new DataflowQueue())
        CH.isChannelQueue(new DataflowBroadcast().createReadChannel())
        !CH.isChannelQueue(new DataflowVariable())
        !CH.isChannelQueue('hello')
    }

    def 'should validate allScalar method' () {

        expect:
        CH.allScalar([1])
        CH.allScalar([1, 2, 3])
        !CH.allScalar([new DataflowVariable(), new DataflowQueue()])
        !CH.allScalar([new DataflowQueue(), new DataflowQueue()])
    }

    def 'should check value' () {
        when:
        def v1 = CH.value()
        then:
        v1 instanceof DataflowVariable
        !v1.isBound()

        when:
        def v2 = runDataflow {
            CH.value('hello')
        }
        then:
        v2 instanceof DataflowVariable
        v2.val == 'hello'
    }

    def 'should bind a value' () {
        given:
        def ch = new DataflowQueue()
        when:
        runDataflow {
            CH.emit(ch, 'hello')
        }
        then:
        ch.val == 'hello'
    }

    def 'should emit a list of values' () {
        given:
        def ch = new DataflowQueue()
        when:
        runDataflow {
            CH.emitValues(ch, [1, 2, 3])
        }
        then:
        ch.val == 1
        ch.val == 2
        ch.val == 3
        and:
        // no stop is emitted
        ch.getVal(500, TimeUnit.MILLISECONDS) == null
    }


    def 'should create dataflow empty queue' () {
        when:
        def ch = CH.queue()
        then:
        ch instanceof DataflowQueue
        and:
        ch.getVal(200, TimeUnit.MILLISECONDS) == null
    }

    def 'should create dataflow queue w/o stop' () {
        given:
        def ch = CH.queue()
        when:
        runDataflow {
            CH.emitValues(ch, [1,2,3])
        }
        then:
        ch instanceof DataflowQueue
        ch.val == 1
        ch.val == 2
        ch.val == 3
        and:
        ch.getVal(200, TimeUnit.MILLISECONDS) == null
    }

    def 'should create dataflow queue with stop' () {
        given:
        def ch = CH.queue()
        when:
        runDataflow {
            CH.emitAndClose(ch, [1,2,3])
        }
        then:
        ch instanceof DataflowQueue
        ch.val == 1
        ch.val == 2
        ch.val == 3
        and:
        ch.val == Channel.STOP
    }

}
