#!/usr/local/bin/ python3
'''
Functions for releasing GENIE consortium releases
'''
import logging
import math
import os
import re
import subprocess
import time

import pandas as pd
import synapseclient
import synapseutils

from . import process_functions

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# GENIE CONSTANTS
# GENIE_RELEASE_DIR = os.path.join(
#    os.path.dirname(os.path.abspath(__file__)),"GENIE_release")
GENIE_RELEASE_DIR = os.path.join(os.path.expanduser("~/.synapseCache"),
                                 "GENIE_release")
CASE_LIST_PATH = os.path.join(GENIE_RELEASE_DIR, 'case_lists')
CNA_CENTER_PATH = os.path.join(GENIE_RELEASE_DIR, "data_CNA_%s.txt")
SAMPLE_CENTER_PATH = os.path.join(GENIE_RELEASE_DIR,
                                  'data_clinical_supp_sample_%s.txt')
PATIENT_CENTER_PATH = os.path.join(GENIE_RELEASE_DIR,
                                   'data_clinical_supp_patient_%s.txt')
MUTATIONS_CENTER_PATH = os.path.join(GENIE_RELEASE_DIR,
                                     'data_mutations_extended_%s.txt')
FUSIONS_CENTER_PATH = os.path.join(GENIE_RELEASE_DIR, 'data_fusions_%s.txt')
SEG_CENTER_PATH = os.path.join(GENIE_RELEASE_DIR,
                               'genie_data_cna_hg19_%s.seg')
BED_DIFFS_SEQASSAY_PATH = os.path.join(GENIE_RELEASE_DIR, 'diff_%s.csv')


def find_caselistid(syn, parentid):
    '''
    Search for case_lists folder based on parentId given

    Args:
        syn: Synapse object
        parentid: Synapse Id of Folder or Project

    Returns:
        string: Synapse id of case list
    '''
    release_ents = synapseutils.walk(syn, parentid)
    release_folders = next(release_ents)
    # if list is empty
    if not release_folders[1]:
        caselist_folder = synapseclient.Folder(name="case_lists",
                                               parent=parentid)
        caselistid = syn.store(caselist_folder).id
    else:
        caselistid = release_folders[1][0][1]
    return caselistid


def store_file(syn, filePath, genieVersion="database", name=None,
               parent=None, fileFormat=None, cBioFileFormat=None):
    '''
    Convenience function to store files

    Args:
        syn: Synapse object
        filePath: path to file to store
        genieVersion: Version of genie release
        name: Name of entity
        fileFormat: GENIE file format
        cBioFileFormat: cBioPortal file format
        staging: Staging GENIE release.  Default to False
        caseLists: Case lists are stored elsewhere
    '''
    logger.info("STORING FILE: {}".format(os.path.basename(filePath)))
    if name is None:
        name = os.path.basename(filePath)
    ent = synapseclient.File(filePath, name=name, parent=parent,
                             versionComment=genieVersion)
    if fileFormat is not None:
        ent.fileFormat = fileFormat
    if cBioFileFormat is not None:
        ent.cBioFileFormat = cBioFileFormat
    ent = syn.store(ent)
    return ent


def _to_redact_interval(df_col):
    """
    Determines interval values that are <18 and >89 that need to be redacted
    Returns bool because BIRTH_YEAR needs to be redacted as well based
    on the results

    Args:
        df_col: Dataframe column/pandas.Series of an interval column

    Returns:
        tuple: pandas.Series: to redact boolean vector
               pandas.Series: to redact pediatric boolean vector

    """
    phi_cutoff = 365*89
    pediatric_cutoff = 365*18
    # Some centers pre-redact their values by adding < or >. These
    # must be redacted
    contain_greaterthan = df_col.astype(str).str.contains(">", na=False)
    contain_lessthan = df_col.astype(str).str.contains("<", na=False)
    # Add in errors='coerce' to turn strings into NaN
    col_int = pd.to_numeric(df_col, errors='coerce')
    to_redact = (col_int > phi_cutoff) | contain_greaterthan
    to_redact_pediatric = (col_int < pediatric_cutoff) | contain_lessthan
    return to_redact, to_redact_pediatric


def _redact_year(df_col):
    """Redacts year values that have < or >

    Args:
        df_col: Dataframe column/pandas.Series of a year column

    Returns:
        pandas.Series: Redacted series

    """
    year = df_col.astype(str)
    contain_greaterthan = year.str.contains(">", na=False)
    contain_lessthan = year.str.contains("<", na=False)
    df_col[contain_greaterthan] = "cannotReleaseHIPAA"
    df_col[contain_lessthan] = "withheld"
    return df_col


def _to_redact_difference(df_col_year1, df_col_year2):
    """Determine if difference between year2 and year1 is > 89

    Args:
        df_col_year1: Dataframe column/pandas.Series of a year column
        df_col_year2: Dataframe column/pandas.Series of a year column

    Returns:
        pandas.Series: to redact boolean vector

    """
    # Add in errors='coerce' to turn strings into NaN
    year1 = pd.to_numeric(df_col_year1, errors='coerce')
    year2 = pd.to_numeric(df_col_year2, errors='coerce')
    to_redact = year2 - year1 > 89
    return to_redact


def redact_phi(clinicaldf, interval_cols_to_redact=['AGE_AT_SEQ_REPORT',
                                                    'INT_CONTACT',
                                                    'INT_DOD']):
    """Redacts the PHI by re-annotating the clinical file

    Args:
        clinicaldf: merged clinical dataframe
        interval_cols_to_redact: List of interval columns to redact.
                                 Defaults to ['AGE_AT_SEQ_REPORT',
                                              'INT_CONTACT',
                                              'INT_DOD']

    Returns:
        pandas.DataFrame: Redacted clinical dataframe

    """
    # Moved to cannotReleaseHIPAA and withheld because the HIPAA
    # years would change every single year. (e.g. <1926, >1998 would be
    # inaccurate every year)
    for col in interval_cols_to_redact:
        to_redact, to_redactpeds = _to_redact_interval(clinicaldf[col])
        clinicaldf.loc[to_redact, 'BIRTH_YEAR'] = "cannotReleaseHIPAA"
        clinicaldf.loc[to_redact, col] = ">32485"
        clinicaldf.loc[to_redactpeds, 'BIRTH_YEAR'] = "withheld"
        clinicaldf.loc[to_redactpeds, col] = "<6570"
    # Redact BIRTH_YEAR values that have < or >
    # Birth year has to be done separately because it is not an interval
    clinicaldf['BIRTH_YEAR'] = _redact_year(clinicaldf['BIRTH_YEAR'])
    to_redact = _to_redact_difference(clinicaldf['BIRTH_YEAR'],
                                      clinicaldf['YEAR_CONTACT'])
    clinicaldf.loc[to_redact, 'BIRTH_YEAR'] = "cannotReleaseHIPAA"
    to_redact = _to_redact_difference(clinicaldf['BIRTH_YEAR'],
                                      clinicaldf['YEAR_DEATH'])
    clinicaldf.loc[to_redact, 'BIRTH_YEAR'] = "cannotReleaseHIPAA"

    return clinicaldf


def configure_maf_row(row_array, headers, keep_samples, remove_variants,
                      flagged_variants):
    """Configures each maf row, does germline filtering

    Args:
        rowArray: Each maf row
        headers: maf Headers
        keepSamples: Samples to keep
        remove_variants: Variants to remove
        flagged_variants: Variants to flag

    Returns:
        configured maf row
    """
    chrom = str(row_array[headers.index('Chromosome')])
    start
 = str(row_array[headers.index('Start_Position')])
    end = str(row_array[headers.index('End_Po
sition')])
    ref = str(row_array[headers.index('Reference_Allele')])
    seq = str(row_array[headers.index('Tumor_Seq_Allele2')])
    sampleid = str(row_array[headers.index('Tumor_Sample_Barcode')])
    hgvsp = str(row_array[headers.index('HGVSp_Short')])
    filter_info = str(row_array[headers.index('FILTER')])
    variant = '{} {} {} {} {} {}'.format(chrom, start, end,
                                         ref, seq, sampleid)
    # Add this line for now because merge check uses
    # different primary key from maf
    mergecheck_variant = '{} {} {} {} {} {}'.format(chrom, start, hgvsp,
                                                    ref, seq, sampleid)
    # if pd.Series(sampleId).isin(keepSamples).any() and \
    # not pd.Series(variant).isin(remove_variants).any():
    if samp