"""There is a set of checkers for handling of correctness of the calibration database"""

import logging
from datetime import datetime
import pandas as pd
import numpy as np
from compton_combiner import SEASONS
from compton_combiner import RunsDBHandler, Combiner
from compton_filter import SlowdbComptonHandler, CalibrdbHandler

def check_season(season, parser):
    """Check correctness of the average calibrations.
    This function tests that all the points of the season are filled in the calibration database and 
    this database has not duplicates.
    
    Parameters
    ----------
    season : str
        a season for checking (can be from `compton_combiner.SEASONS` enum)
    parser : Configparser
        configparser of the toml file with credentials
    """
    
    idx = SEASONS['name'].index(season)
    start_run, stop_run = SEASONS['start_run'][idx], SEASONS['start_run'][idx + 1]
    logging.info(f'Season {season}, runs from {start_run} to {stop_run}')
    
    rdb = RunsDBHandler(**parser['cmdruns'])
    rdb_df = rdb.load_tables((start_run, stop_run))
    trng = (rdb_df[0][-1][1], rdb_df[0][0][2])
    logging.info(f'Runs table has been loaded. \n\
First row is {rdb_df[0][-1][0]} run (at {rdb_df[0][-1][1].strftime("%Y-%m-%d")}), \
last row is {rdb_df[0][0][0]} run (at {rdb_df[0][0][1].strftime("%Y-%m-%d")}). \n\
Total rows {len(rdb_df[0])}, unique energies {sum(map(lambda x: x[0][3]!=x[1][3], zip(rdb_df[0][1:], rdb_df[0][:-1]))) + 1}' )
    
    rdb_df = pd.DataFrame(rdb_df[0], columns=rdb_df[1]).sort_values(by='run')
    rdb_df['eprev'] = rdb_df.energy.shift(1).fillna(-1)
    rdb_df['enext'] = rdb_df.energy.shift(-1).fillna(-1)
    
    # start_runs_df = rdb_df.drop_duplicates(subset=['energy'], keep='first')
    # end_runs_df = rdb_df.drop_duplicates(subset=['energy'], keep='last')
    
    good_mask = np.invert(np.isclose(rdb_df['energy'], rdb_df['eprev']) & np.isclose(rdb_df['energy'], rdb_df['enext']))
    rdb_df = rdb_df.loc[good_mask].drop(['eprev', 'enext'], axis=1)
    rdb_df = pd.concat([rdb_df.iloc[::2].reset_index(drop=True).rename({'run': 'firstrun'}, axis=1)[['energy', 'firstrun']], 
           rdb_df.iloc[1::2].reset_index(drop=True).rename({'run': 'lastrun'}, axis=1)[['lastrun']]], axis=1).assign(goods=1)
    
    clbrdb = CalibrdbHandler(**parser['clbrDB'])
    # trng = (rdb_df.starttime.min(), rdb_df.stoptime.max())
    logging.info(f'Time range from {trng[0]} to {trng[1]}')
    # print(trng)
    res_clbrdb = clbrdb.load_table('Misc', 'RunHeader', 'Compton_run_avg', num_last_rows = None, timerange = trng)
    clbr_df = pd.DataFrame(res_clbrdb[0], columns=res_clbrdb[1]).drop(['cid', 'sid', 'createdby', 'parameters'], axis=1).sort_values(by='time')
    clbr_df = clbr_df.apply(
        lambda x: pd.Series([x['comment'], x['time'], x['data'][0], x['data'][1], x['data'][2], round(x['data'][3], 3)], 
                            index=['pname', 'time', 'energy', 'firstrun', 'lastrun', 'emeas']), 
        axis=1).reset_index(drop=True)
    
    concat_df = pd.merge(clbr_df, rdb_df, on=['firstrun', 'lastrun'], how='outer')
    concat_df.loc[concat_df.isna().max(axis=1), 'goods'] = 0
    concat_df.goods = concat_df.goods.astype(int)
    
    nbads = sum(concat_df.goods==0)
    if nbads > 0:
        logging.warning(f'{sum(concat_df.goods==0)} bad rows are found')
    else:
        logging.info(f'bad rows are not found')
    
    
    return concat_df

if __name__=="__main__":
    import argparse
    import sys
    from configparser import ConfigParser
    
    log_format = '[%(asctime)s] %(levelname)s: %(message)s'
    logging.basicConfig(stream=sys.stdout, format=log_format, level=logging.INFO) #"filename=compton_combiner.log"
    logging.info("compton_checker is started")
    
    parser = argparse.ArgumentParser(description = 'Checker of the energy measurement calibrations')
    parser.add_argument('-s', '--season', help = 'Name of the season')
    parser.add_argument('-c', '--config', help = 'Config file containing information for access to databases')
    
    args = parser.parse_args()
    logging.info(f"""Arguments: season {args.season}, config {args.config}""")
    
    parser = ConfigParser()
    parser.read(args.config);
    
    res_df = check_season(args.season, parser)
    
    with pd.option_context('display.max_rows', None,):
        print(res_df)
    