"""
Generate a random FASTA file
"""
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

import argparse
import hashlib
import json
import math
import os
import random

import utils


class FastaGenerator(object):
    """
    Generates a random FASTA file and metadata json.
    """
    def __init__(self, args):
        self.numBases = args.num_bases
        self.outputPrefix = args.output_prefix
        self.fastaFileName = "{}.fa".format(self.outputPrefix)
        self.referenceId = os.path.split(args.output_prefix)[-1]
        self.bases = ""

    def writeFasta(self):
        """
        Write the random fasta file
        """
        utils.log("writing {} bases to {} ...".format(
            self.numBases, self.fastaFileName))
        with open(self.fastaFileName, 'w') as fastaFile:
            firstLine = ">{} Generated by generate_fasta.py".format(
                self.referenceId)
            print(firstLine, file=fastaFile)
            basesPerLine = 70
            numLines = int(math.ceil(self.numBases / basesPerLine))
            baseChoices = ['A', 'G', 'C', 'T']
            basesRemaining = self.numBases
            for i in range(numLines):
                if basesRemaining < basesPerLine:
                    basesToWrite = basesRemaining
                else:
                    basesToWrite = basesPerLine
                bases = ''.join(
                    [random.choice(baseChoices) for _ in range(basesToWrite)])
                line = "{}".format(bases)
                self.bases += line
                print(line, file=fastaFile)
                basesRemaining -= basesToWrite
            assert basesRemaining == 0

    def writeMetadata(self):
        """
        Write some metadata.
        """
        metadata = {
            "md5checksum": hashlib.md5(self.bases).hexdigest(),
            "sourceUri": "http://example.com/random_url",
            "ncbiTaxonId": random.randint(1, 10000),
            "isDerived": False,
            "sourceDivergence": None,
            "sourceAccessions": [],
        }
        jsonFileName = "{}.json".format(self.outputPrefix)
        utils.log("writing metadata to {} ...".format(jsonFileName))
        with open(jsonFileName, "w") as jsonFile:
            json.dump(metadata, jsonFile, indent=4)

    def zipFasta(self):
        """
        Compress the fasta file
        """
        utils.log("zipping {} ...".format(self.fastaFileName))
        cmd = "bgzip -f {}".format(self.fastaFileName)
        utils.runCommand(cmd)

    def indexFasta(self):
        """
        Create index on the fasta file
        """
        zipFileName = "{}.gz".format(self.fastaFileName)
        utils.log("indexing {} ...".format(zipFileName))
        cmd = "samtools faidx {}".format(zipFileName)
        utils.runCommand(cmd)

    def generate(self):
        self.writeFasta()
        self.writeMetadata()
        self.zipFasta()
        self.indexFasta()


@utils.Timed()
def main():
    requiredExecutables = ['bgzip', 'samtools']
    utils.requireExecutables(requiredExecutables)
    parser = argparse.ArgumentParser(
        description="Generate random FASTA files and metadata")
    parser.add_argument(
        "output_prefix", help="The prefix for generated files.")
    basesDefault = 1000
    parser.add_argument(
        "--num-bases", "-n", default=basesDefault,
        help="number of bases to include; default {}".format(basesDefault))
    fastaGenerator = FastaGenerator(parser.parse_args())
    fastaGenerator.generate()


if __name__ == '__main__':
    main()
