from loguru import logger
from datetime import datetime, timedelta
from scripts.core.data.data_import import DataPuller
from scripts.constants.app_configuration import KAIROS_DB_HOST, data_conf, OUTPUT_PARAMETER_QUICK_MAP_INFO, KAFKA_TOPIC, OUTPUT_SITE_ID, TARGET_VALUE
from scripts.core.recommender.parameter_optimizer import ParameterOptimization
import simplejson
from scripts.data_model.egress_data_model import KafkaDataModel
from scripts.core.data.data_export import KafkaProducerUtil


def get_start_time_and_end_time():
    logger.info("Finding the start and end time for the data fetch - relative recent data")
    # Time Intervals
    # 01:00-01:15, 01:15-01:30, 01:30-01:45, 01:45-02:00
    current_time = datetime.now()
    if current_time.minute >= 45:
        # timeframe to consider 30-45
        start_time_value = current_time.replace(minute=30, second=0, microsecond=0)
    elif current_time.minute >= 30:
        # timeframe to consider 15-30
        start_time_value = current_time.replace(minute=15, second=0, microsecond=0)
    elif current_time.minute >= 10:
        # timeframe to consider 00-15
        start_time_value = current_time.replace(minute=0, second=0, microsecond=0)
    else:
        # timeframe to consider 45-00
        start_time_value = current_time.replace(minute=45, second=0, microsecond=0)
        start_time_value = start_time_value - timedelta(hours=1, minutes=0)
    start_time = start_time_value
    end_time = start_time + timedelta(hours=0, minutes=14, seconds=59)
    start_time = start_time.timestamp() * 1000
    end_time = end_time.timestamp() * 1000
    return start_time, end_time


def recommend_best_parameters():
    logger.info("Started Recommending best Parameters")
    start_time, end_time = get_start_time_and_end_time()
    prediction_time_difference = 15 * 60 * 1000
    prediction_time_difference_end = 1000 * 60 * 30
    absolute_time = {"start_absolute": start_time, "end_absolute": end_time}
    logger.debug("Fetching most recent live data")
    live_data_puller = DataPuller(db_host=KAIROS_DB_HOST,
                                  data_config=data_conf,
                                  payload="live_query",
                                  absolute_time=absolute_time)
    df_input = live_data_puller.get_data()
    df_input["Bharuch-Unit 2.CTCMP.Stage IIA - Chlorination & Neutralization-I.Reactor R-7204.total_chlorine_flow"] = \
        df_input["Bharuch-Unit 2.CTCMP.Stage IIA - Chlorination & Neutralization-I.Reactor R-7204.Flow 3"] + \
        df_input["Bharuch-Unit 2.CTCMP.Stage IIA - Chlorination & Neutralization-I.Reactor R-7204.Flow 5"]
    data_dict = df_input.to_dict(orient="records")
    logger.debug("Input Data Received")
    optimizer = ParameterOptimization()
    recommendation_flag, recommendation_result, predicted_result = optimizer.find_optimum(data_dict=data_dict,
                                                                                          controllable=True,
                                                                                          add_predict=TARGET_VALUE)
    logger.debug("Obtained optimized result from Optimizer")
    logger.debug("Output Recommendation : {}".format(simplejson.dumps(recommendation_result, allow_nan=False)))
    logger.debug("Output Prediction : {}".format(simplejson.dumps(predicted_result, allow_nan=False)))
    logger.debug("Tagging the data appropriately to be shared to Kafka/DataProcessor")
    tagged_recommendation_result = dict()
    tagged_predicted_result = dict()
    for each_parameter in OUTPUT_PARAMETER_QUICK_MAP_INFO:
        if each_parameter in recommendation_result:
            tagged_recommendation_result[OUTPUT_PARAMETER_QUICK_MAP_INFO[each_parameter]] = recommendation_result[
                each_parameter]
        if each_parameter in predicted_result:
            tagged_predicted_result[OUTPUT_PARAMETER_QUICK_MAP_INFO[each_parameter]] = predicted_result[each_parameter]

    print(tagged_recommendation_result)
    print(tagged_predicted_result)

    recommendation_time = end_time + 1
    prediction_time_start = recommendation_time + prediction_time_difference
    prediction_time_end = recommendation_time + prediction_time_difference_end
    recommendation_output = KafkaDataModel(data=tagged_recommendation_result,
                                           site_id=OUTPUT_SITE_ID,
                                           timestamp=int(recommendation_time))
    logger.info("Recommendation Output : {}".format(simplejson.dumps(recommendation_output.dict(), allow_nan=False)))

    predicted_output_start = KafkaDataModel(data=tagged_predicted_result,
                                            site_id=OUTPUT_SITE_ID,
                                            timestamp=int(prediction_time_start))
    predicted_output_end = KafkaDataModel(data=tagged_predicted_result,
                                          site_id=OUTPUT_SITE_ID,
                                          timestamp=int(prediction_time_end))
    logger.info("Prediction Output Start : {}".format(simplejson.dumps(predicted_output_start.dict(), allow_nan=False)))
    logger.info("Prediction Output End : {}".format(simplejson.dumps(predicted_output_end.dict(), allow_nan=False)))
    kafka_writer = KafkaProducerUtil()
    if recommendation_flag:
        kafka_writer.publish(topic=KAFKA_TOPIC, data=simplejson.dumps(recommendation_output.dict(), allow_nan=False))
        kafka_writer.publish(topic=KAFKA_TOPIC, data=simplejson.dumps(predicted_output_start.dict(), allow_nan=False))
        kafka_writer.publish(topic=KAFKA_TOPIC, data=simplejson.dumps(predicted_output_end.dict(), allow_nan=False))
        logger.info("Outputs written to Kafka successfully!")
    else:
        logger.info("Outputs not written as recommendations flag was false!")


if __name__ == '__main__':
    recommend_best_parameters()
