import h5py
import numpy as np
import argparse
import sys
from camel.wrap.sample import Sample
from collections import defaultdict
from natsort import natsorted

def run(args):
    return run_direct(args.index, args.input, args.bed, args.region, args.nogl)


def run_direct(index_filename, input_filenames, bed_filename=None, region=None, nogl=False):
    samples = [Sample(filename) for filename in input_filenames]

    index = h5py.File(index_filename, "r")

    print("#chrom", "start", "stop", "n_cpg", sep="\t", end="\t")
    print(*samples, sep="\t")

    dmrs = defaultdict(list)

    if region:
        if region.find(":") == -1:
            chrom = region
            start, stop = 0, index[chrom]["cpg_positions"][-1]
        else:
            chrom, start_stop = region.split(":")
            start, stop = map(int, start_stop.split("-"))
        dmrs[chrom].append((start, stop, 0))
    elif bed_filename:
        for i, line in enumerate(open(bed_filename, "r")):
            line = line.strip()
            if len(line) < 2: #skip empty lines
                continue

            if line.startswith("#"): #skip comments
                continue

            split = line.split("\t")
            if len(split) < 3:
                continue

            chrom, start, stop = split[:3]
            if chrom.startswith("chr"):
                chrom = chrom[3:]
            start = int(start)
            stop = int(stop)

            dmrs[chrom].append((start, stop, i))
    else:
        for chrom in index:
            if nogl and chrom.startswith("GL"):
                continue
            if chrom in ["X", "Y"]:
                continue
            stop = index[chrom]["cpg_positions"][-1]
            dmrs[chrom].append((1, stop, 0))

    output = []

    for chrom in natsorted(dmrs):
        if chrom not in samples[0].chromosomes():
            print("WARNING: {chrom} not in camel file".format(chrom=chrom), file=sys.stderr)
            continue

        chrom_dmrs = np.array(dmrs[chrom])
        indices = np.searchsorted(index[chrom]["cpg_positions"][:], chrom_dmrs[:,0:2])
        m_values = np.array([s.m_values(chrom) for s in samples]).T

        for (start, stop, n), (start_index, stop_index) in zip(dmrs[chrom], indices):
            #output.append((n, chrom, start, stop, stop_index-start_index, *(np.sum(m_values[start_index:stop_index], axis=0) / (stop_index-start_index))))
#            print(np.median(np.std(m_values[start_index:stop_index], axis=0)))
            output.append((n, chrom, start, stop, stop_index-start_index, np.median(np.std(m_values[start_index:stop_index], axis=0))))
            #print(chrom, start, stop, stop_index-start_index, sep="\t", end="\t")
            #print(*(np.sum(m_values[start_index:stop_index], axis=0) / (stop_index-start_index)), sep="\t")
#            averages = [round(np.average(s.m_values(chrom, start_index, stop_index)),2) for s in samples]
#            print(*averages, sep="\t")
    for x in sorted(output):
        print(*x[1:], sep="\t")


def sub(parser):
    parser.add_argument('index', help='the camel index')
    parser.add_argument('input', nargs='+', help='the samples of which to build the average of')
    parser.add_argument('--bed', help='a bed file with regions')
    parser.add_argument('-r', '--region', help='a region in the form of chr:start-stop')
    parser.add_argument('-nogl', action="store_true", help='ignore chromosomes with prefix "GL"', default=False)


def main():
    parser = argparse.ArgumentParser()
    sub(parser)
    args = parser.parse_args()
    run(args)


if __name__ == "__main__":
    main()
