from builtins import str
from mined_metric.builder import metric_hub_binding as mh

'''
Map reduce script to mine over all SLAC CR runs for any given release.
Results will be written to text files in the output directory.
'''

import argparse
from datetime import datetime
import errno
import json
import os
from psycopg2 import sql
import requests
import subprocess
import sys

import logging
from base.logging import zoox_logger
from google.protobuf.json_format import MessageToDict
from mapreduce.key_value_data import run_argparser, KeyValueData
import mined_metric.builder.prc_metrics.utils as utils

log = logging.getLogger(__name__)

def parse_args():
    parser = argparse.ArgumentParser(description='run metric prc miner')
    parser.add_argument('--metric', '-m', type=str, required=True, help='Metric to mine for.')
    parser.add_argument('--release', '-r', type=str, default=None, required=False, help='Only mine runs from the given release. If not provided, miner will mine all runs between last event in redshift to current time.')
    parser.add_argument('--num_workers', '-w', type=int, default=10, help='Number of workers to use for the mining tasks.')
    parser.add_argument('--output_dir', '-o', type=str, required=True, help='Output directory.')

    return run_argparser(parser)


'''
Get all the SLAC Challenge route runs for the given release
'''
def get_run_ids(release):
    sql_str = "SELECT hr_id from runs where tracking_category='{}' and release='{}' ORDER BY hr_id".format('SLAC Challenge Route', release)

    results = utils.run_sql(sql.SQL(sql_str))
    return [r[0] for r in results]


def mine(task, metric, output_dir):
    uri = task.value()
    log.info('Mining {}'.format(uri))
    res = mh.mine_run(metric, uri)
    with open(os.path.join(output_dir, uri+'.txt'), 'w') as f:
        for r in res:
            f.write(r + '\n')




def create_mr(runs_to_mine, metric, output_dir, num_workers):
    if len(runs_to_mine) == 0:
        log.info("No runs to mine")
        return

    # The docker run flag is a temporary fix for the static TLS memory issues
    mr = KeyValueData.from_values(runs_to_mine)\
            .map(lambda x: mine(x, metric, output_dir))\
            .with_num_task_splits(len(runs_to_mine))\
            .with_num_workers(num_workers)\
            .with_per_task_time_limit(18000)\
            .with_name("ped_cw_mr_miner")\
            .with_docker_run_flag("-e LD_PRELOAD=/usr/local/lib/x86_64-linux-gnu/libGL.so.1:/usr/lib/x86_64-linux-gnu/libgomp.so.1")
    mr.run()


if __name__ == "__main__":
    args = parse_args()
    runs_to_mine = get_run_ids(args.release)
    try:
      os.makedirs(args.output_dir)
    except OSError as e:
      if e.errno != errno.EEXIST:
         raise
      else:
         log.info('Output directory already exists...')
    try:
        os.chmod(args.output_dir, 0o777)
    except:
        log.info('Not able to change permissions... Proceeding...')

    if len(runs_to_mine) == 0:
        log.warning("Did not find any new runs to mine.")
    else:
        log.info("Mining " + str(len(runs_to_mine)) + " runs")
        create_mr(runs_to_mine, args.metric, args.output_dir, args.num_workers)
