workflow run_wf {

  take: in_

  main:

    out_ = in_
      | flatMap{ id, state ->
        println "Looking for fastq files in ${state.input}"
        def allFastqs = state.input
          .listFiles()
          .findAll{
            it.isFile() &&
            it.name ==~ /^.+\.fastq.gz$|^.+\.fastq$|^.+\.fasta$/
          }
        println "Found ${allFastqs.size()} fastq/fasta files in ${state.input}"
        assert allFastqs.size() > 0: "No fastq/fasta files found"

        println("Extracting information from fastq/fasta filenames")
        def processed_fastqs = allFastqs.collect { f ->
          def regex = ~/^(\S+)_S(\d+)_(L(\d+)_)?R(\d)_(\d+)\.fast[qa](\.gz)?$/
          def validFastq = f.name ==~ regex

          assert validFastq: "${f} does not match the regex ${regex}"

          def parsedFastq = f.name =~ regex
          def lane = parsedFastq[0][3]
          // Remove the trailing '_'
          def lane_remove_trailing = lane == null ? "" : lane.replaceAll('_$', "")
          def sample_id = parsedFastq[0][1]
          if (sample_id in ["Undetermined"] || (state.pools && !state.pools.isEmpty() && !state.pools.contains(sample_id))) {
            return null
          }
          return [
            "fastq": f,
            "sample_id": sample_id,
            "sample": parsedFastq[0][2],
            "lane": lane_remove_trailing,
            "read": parsedFastq[0][5],
          ]
        }

        println("Group paired fastq/fasta files")
        def grouped = processed_fastqs
          .findAll{it != null}
          .groupBy({it.sample_id}, {it.lane})
          .collect{ sample_id, states_per_lane ->
            // states_per_lane is a hashmap with the lane ID as keys and a tuple of length 2 (forwards and reverse FASTQ)
            assert states_per_lane.each{lane, lane_states -> lane_states.size() == 2}, "Expected to find two fastq files per lane! Found ${states_per_lane}."
            // gather the FASTQ files across the lanes
            def empty_result = ["r1_output": [], "r2_output": [], "lane": []]
            def fastq_output = states_per_lane.inject(empty_result){ current_state, lane_id, lane_states ->
              assert lane_states.size() == 2, "Expected to find two fastq files per lane! " +
                "Found ${lane_states.size()}. State: ${states_per_lane}"
              def r1_fastq = lane_states.find({it.read == "1"}).fastq
              def r2_fastq = lane_states.find({it.read == "2"}).fastq
              def new_state = [
                "r1_output": current_state["r1_output"] + [r1_fastq],
                "r2_output": current_state["r2_output"] + [r2_fastq],
                "lane": current_state["lane"] + lane_id
              ]
              return new_state
            }
            // Use one of the lanes as template for the output
            def base_state = states_per_lane.values()[0][0].subMap(["sample_id", "sample"])
            
            return [sample_id, base_state + ["_meta": ["join_id": id]] + fastq_output]
          }
          return grouped
      }

  emit: out_

}
