from unittest import TestCase, main
from os.path import join, abspath, dirname
from os import environ
import subprocess

from biom import load_table
from deblur.workflow import sequence_generator
from tempfile import mkdtemp


def _system_call(cmd):
    # this is a wrapper so tests pass in the github actions
    cmd = '  '.join(cmd)

    conda_env = environ.get('CONDA_DEFAULT_ENV')
    if conda_env is not None:
        cmd = f"bash -c '. ~/.profile; conda activate {conda_env}; {cmd};'"

    proc = subprocess.Popen(cmd, universal_newlines=True, shell=True,
                            stdout=subprocess.PIPE, stderr=subprocess.PIPE)

    stdout, stderr = proc.communicate()
    return_value = proc.returncode

    if stderr != 0:
        print(cmd)
        print(stdout, stderr, return_value)

    return stdout, stderr, return_value


class TestScript(TestCase):

    def setUp(self):
        self.data_dir = join(dirname(abspath(__file__)), 'data')
        self.seqs_fp = join(self.data_dir, 'seqs_s5.fasta')
        self.orig_fp = join(self.data_dir, 'simset.s3.fasta')
        self.orig_one_seq_fp = join(self.data_dir, 'simset.s5.fasta')
        self.output_dir = mkdtemp()
        self.output_biom = join(self.output_dir, 'all.biom')
        self.output_seqs = join(self.output_dir, 'all.seqs.fa')
        self.trim_length = 150

    def validate_results(self, table_name, orig_fasta_name):
        res_table = load_table(table_name)

        res_seqs = list(res_table.ids(axis='observation'))
        exp_seqs = [item[1] for item in sequence_generator(orig_fasta_name)]
        exp_seqs = list(map(lambda x: x.upper()[:self.trim_length], exp_seqs))
        self.assertListEqual(res_seqs, exp_seqs)

    def test_workflow(self):
        # test default parameters, negative mode, single thread
        cmd = ["deblur", "workflow", "--seqs-fp", self.seqs_fp,
               "--output-dir", self.output_dir,
               "--trim-length", "150", '-w']
        sout, serr, res = _system_call(cmd)
        self.validate_results(self.output_biom, self.orig_one_seq_fp)

        # test default parameters, negative mode, multi thread
        cmd = ["deblur", "workflow", "--seqs-fp", self.seqs_fp,
               "--output-dir", self.output_dir,
               "--trim-length", "150", '-w',
               "-O", "2"]
        sout, serr, res = _system_call(cmd)
        self.validate_results(self.output_biom, self.orig_one_seq_fp)

        # test default parameters, positive mode, single thread
        cmd = ["deblur", "workflow", "--seqs-fp", self.seqs_fp,
               "--output-dir", self.output_dir,
               "--trim-length", "150", '-w']
        sout, serr, res = _system_call(cmd)
        self.validate_results(self.output_biom, self.orig_one_seq_fp)

        # test default parameters, positive mode, multi thread
        cmd = ["deblur", "workflow", "--seqs-fp", self.seqs_fp,
               "--output-dir", self.output_dir,
               "--trim-length", "150", '-w',
               "-O", "2"]
        sout, serr, res = _system_call(cmd)
        self.validate_results(self.output_biom, self.orig_one_seq_fp)

        # test default parameters except min-reads set to 0, negative mode,
        # single thread
        cmd = ["deblur", "workflow", "--seqs-fp", self.seqs_fp,
               "--output-dir", self.output_dir,
               "--trim-length", "150", '-w', '--min-reads', '0']
        sout, serr, res = _system_call(cmd)
        self.validate_results(self.output_biom, self.orig_fp)


if __name__ == "__main__":
    main()
