#!/usr/bin/env python3
# -*- coding: utf-8 -*-
""" Tools module with functions related to plots """

from datetime import datetime
from datetime import timedelta
import os
import logging

from map_handler import MapHandler
from map_handler import ForecastModelsFigureHandler
from map_handler import ForecastProbFigureHandler
from map_handler import ForecastWasFigureHandler
from map_handler import EvaluationGroundFigureHandler
from map_handler import EvaluationSatelliteFigureHandler
from map_handler import EvaluationStatisticsFigureHandler
from map_handler import VisFigureHandler
from map_handler import DEBUG
from map_handler import MODELS
from map_handler import PATHS
from map_handler import END_DATE, DELAY, DELAY_DATE
from timeseries_handler import ForecastModelsTimeSeriesHandler
from timeseries_handler import EvaluationGroundTimeSeriesHandler

def download_image_link(models, variable, curdate, tstep=0, anim=False):
    """ Generates links to animated gifs

    Parameters
    ----------
    models : str, list
        Model name or list of model names
    variable : str
        Variable name
    curdate : str
        Current date
    tstep : int, optional
        Timestep, by default 0
    anim : bool, optional
        Indicates if we want to create an animation or an image, by default False

    Returns
    -------
    str
        Filename of the image / animation
    """

    logging.debug('CURRDIR %s', os.getcwd())
    filepath = "assets/comparison/{model}/{variable}/{year}/{month}/{curdate}_{model}_{tstep}.{ext}"

    if len(models) == 1:
        model = models[0]
        logging.debug('DOWNLOAD MODELS %s', model)
    else:
        logging.debug('DOWNLOAD ALL MODELS')
        model = "all"
    if anim:
        tstep = "loop"
        ext = "gif"
        logging.debug('DOWNLOAD LOOP')
    else:
        tstep = "%02d" % tstep
        ext = "png"
        logging.debug('DOWNLOAD PNG %s', tstep)

    filename = filepath.format(
                model=model,
                variable=variable.lower(),
                year=curdate[:4],
                month=curdate[4:6],
                curdate=curdate,
                tstep=tstep,
                ext=ext
            )
    logging.debug('DOWNLOAD FILENAME %s', filename)
    
    return filename 


def get_eval_timeseries(obs, start_date, end_date, var, idx, station_name, model):
    """ Retrieve timeseries in the evaluation visual comparison map

    Parameters
    ----------
    obs : str
        Observations name
    start_date : str
        Start date
    end_date : str
        End date
    var : str
        Variable name
    idx : int
        Station index
    station_name : str
        Station name
    model : str, optional
        Model name, by default None

    Returns
    -------
    go.Figure
        Modal window with timeseries
    """

    logging.debug('SERVER: OBS TS init for obs %s ... ', str(obs))
    th = EvaluationGroundTimeSeriesHandler(obs, start_date, end_date, var)
    logging.debug('SERVER: OBS TS generation ... ')

    return th.retrieve_timeseries(idx, station_name, model)


def get_timeseries(model, date, var, lat, lon, forecast=False):
    """ Retrieve timeseries in the forecast models maps

    Parameters
    ----------
    model : str
        Model name
    date : str
        Selected date
    var : str
        Variable name
    lat : float
        Latitude
    lon : float
        Longitude
    forecast : bool, optional
        Indicates if we are using forecast data, by default False

    Returns
    -------
    go.Figure
        Modal window with timeseries
    """

    logging.debug('SERVER: TS init for models %s ... ', str(model))
    th = ForecastModelsTimeSeriesHandler(model, date, var)
    logging.debug('SERVER: TS generation ... ')

    return th.retrieve_timeseries(lat, lon, method='feather', forecast=forecast)


def get_single_point(model, date, tstep, var, lat, lon):
    """ Retrive data on single point

    Parameters
    ----------
    model : str
        Model name
    date : str
        Selected date
    tstep : int
        Timestep
    var : str
        Variable name
    lat : float
        Latitude
    lon : float
        Longitude

    Returns
    -------
    float
        Variable value at closest available point from (lat, lon)
    """

    logging.debug('SERVER: SINGLE POINT init for models %s ... ',str(model))
    th = ForecastModelsTimeSeriesHandler(model, date, var)
    logging.debug('SERVER: SINGLE POINT generation ... ')

    return th.retrieve_single_point(tstep, lat, lon)


def get_evaluation_comparison_aeronet_figure(start_date, end_date, obs, var):
    """ Retrieve evaluation visual comparison data and figure layers (ground observations from AERONET)

    Parameters
    ----------
    start_date : str
        Start date
    end_date : str
        End date
    obs : str
        Observations name
    var : str
        Variable name

    Returns
    -------
    pandas.core.frame.DataFrame
        Dataframe with stations information
    list
        Figure layers
    """

    fh = EvaluationGroundFigureHandler(start_date, end_date, obs, var)
    
    return fh.get_figure_layers()


def get_evaluation_comparison_modis_figure(var, obs, tstep=0, selected_date=END_DATE):
    """ Retrieve evaluation visual comparison figure layers (satellite observations from MODIS)

    Parameters
    ----------
    var : str
        Variable name
    obs : str
        Observations name
    tstep : int, optional
        Timestep, by default 0
    selected_date : _type_, optional
        Selected date, by default END_DATE

    Returns
    -------
    list
        Figure layers
    """

    fh = EvaluationSatelliteFigureHandler(var, obs, tstep, selected_date)
    
    return fh.get_figure_layers()


def get_evaluation_statistics_figure(network=None, model=None, statistic=None, selection=None):
    """ Retrieve evaluation statistics figure layers

    Parameters
    ----------
    network : str, optional
        Network name, by default None
    model : str, optional
        Model name, by default None
    statistic : str, optional
        Statistic name, by default None
    model : str, optional
        Model name, by default None
    selection : str, optional
        Period selection, by default None

    Returns
    -------
    list
        Figure layers
    """
    
    logging.debug('SERVER: SCORES Figure init ... ')
    fh = EvaluationStatisticsFigureHandler(network, statistic, model, selection=selection)
    
    if network and model and statistic:
        logging.debug('SERVER: SCORES Figure generation ... ')
    else:
        logging.debug('SERVER: NO SCORES Figure')
    
    return fh.get_figure_layers()


def get_currdate_tstep(model_start, model_start_before, current_time_before, delay, selected_date, 
                       tstep=4):
    """ Returns current date and timestep 

    Parameters
    ----------
    model_start : int
        Model start hour
    model_start_before : int
        Model start hour before run
    current_time_before : _type_
        Current time before run
    delay : bool
        Indicates if there is a delay
    selected_date : str
        Selected date
    tstep : int, optional
        Timestep, by default 4

    Returns
    -------
    datetime.datetime
        Selected date
    int
        Timestep
    str
        Timesteps
    """

    # MODELS starting at 00 with 3 days of forecast
    logging.debug("Starting at 0 and NOT DELAYED: 3 days forecast!")
    cdo_tsteps = "1/25"
    delayed = (current_time_before and not delay) or (not current_time_before and delay)

    # MODELS not starting at 00
    if (model_start == 12 and not model_start_before) or \
            (current_time_before and model_start_before == 12):
        if delayed:
            logging.debug("Starting at 12 and DELAYED: 2 days forecast!")
            # DELAYED (2 days): models that starts at 12h considering end_date = current_date - 1
            if tstep < 4:
                selected_date = (datetime.strptime(selected_date, "%Y%m%d") -
                                 timedelta(days=1)).strftime("%Y%m%d")
                tstep = int(tstep) + 4
            else:
                tstep = int(tstep) - 4
            cdo_tsteps = "1/21"
        else:
            logging.debug("Starting at 12 and NOT DELAYED: 3 days forecast!")
            # NOT DELAYED (3 days): models that starts at 12h considering end_date = current_date
            selected_date = (datetime.strptime(selected_date, "%Y%m%d") -
                             timedelta(days=1)).strftime("%Y%m%d")
            tstep = int(tstep) + 4
            cdo_tsteps = "5/29"
    # MODELS starting at 00 with 2 days of forecast
    elif delayed:
        logging.debug("Starting at 0 and DELAYED: 2 days forecast!")
        cdo_tsteps = "5/25"

    return selected_date, tstep, cdo_tsteps


def get_model_figure(var, model, tstep=0, hour=None, selected_date=END_DATE, aspect=(1, 1)):
    """ Retrieve forecast models figure layers

    Parameters
    ----------
    var : str
        Variable name
    model : str
        Model name
    tstep : int, optional
        Timestep, by default 0
    hour : int, optional
        Hour, by default None
    selected_date : str, optional
        Selected date, by default END_DATE
    aspect : tuple, optional
        Map aspect, by default (1,1)

    Returns
    -------
    list
        Figure layers
    """

    logging.debug("*** %s %s %s %s %s *****", model, var, selected_date, tstep, hour)

    try:
        selected_date = datetime.strptime(
            selected_date, "%Y-%m-%d").strftime("%Y%m%d")
    except:
        pass

    if model in MODELS:
        model_start = MODELS[model]['start']
        model_start_before = ('start_before' in MODELS[model]) and MODELS[model]['start_before'] or False
        current_time_before = (DELAY_DATE and datetime.strptime(selected_date, "%Y%m%d") < datetime.strptime(DELAY_DATE, "%Y%m%d"))
        logging.debug(f"""
              ***************************** SERVER: Figure init *******************************
              * DELAY: {DELAY}, DELAY_DATE: {DELAY_DATE}, SELECTED DATE: {selected_date}, CURR_BEFORE: {current_time_before}    *
              * MODEL: {model}, MODEL_START: {model_start}, MODEL_START_DELAYED: {model_start_before} *
              *********************************************************************************
              """)
        # If current date is later than the delay date and the model_start is 12
        # or current date is before than the delay date and the model_start
        selected_date, tstep, _ = get_currdate_tstep(model_start, model_start_before, current_time_before, DELAY, selected_date, tstep)

    logging.debug(' %s %s %s %s %s', var, model, tstep, hour, selected_date)
    if var:
        logging.debug('SERVER: MODELS Figure init ... ')
        fh = ForecastModelsFigureHandler(var=var, model=model, tstep=tstep, hour=hour, selected_date=selected_date)
        logging.debug('SERVER: MODELS Figure generation ... ')
        return fh.get_figure_layers(tstep=tstep, hour=hour, aspect=aspect)

    logging.debug('SERVER: NO MODELS Figure')

    return ForecastModelsFigureHandler().get_figure_layers()


def get_prob_figure(var, prob=None, day=0, selected_date=END_DATE):
    """ Retrieve probability figure layers

    Parameters
    ----------
    var : str, optional
        Variable name, by default None
    prob : float, optional
        Probability threshold, by default None
    day : int, optional
        Day, by default 0
    selected_date : str, optional
        Selected date, by default END_DATE

    Returns
    -------
    list
        Figure layers
    """

    logging.debug(' %s %s %s',prob, day, selected_date)
    try:
        selected_date = datetime.strptime(
            selected_date, "%Y-%m-%d").strftime("%Y%m%d")
    except:
        pass
    logging.debug(' %s %s %s', prob, day, selected_date)

    if prob:
        logging.debug('SERVER: PROB Figure init ... ')
        fh = ForecastProbFigureHandler(var=var, prob=prob, selected_date=selected_date)
        logging.debug('SERVER: PROB Figure generation ... ')
        return fh.get_figure_layers(day=day)

    logging.debug('SERVER: NO PROB Figure')

    return ForecastProbFigureHandler().get_figure_layers()


def get_was_figure(was=None, day=0, selected_date=END_DATE):
    """ Retrieve WAS figure layers

    Parameters
    ----------
    was : str, optional
        Region name, by default None
    day : int, optional
        Day, by default 0
    selected_date : str, optional
        Selected date, by default END_DATE

    Returns
    -------
    list
        Figure layers
    """

    logging.debug(' %s %s %s', was, day, selected_date)
    try:
        selected_date = datetime.strptime(
            selected_date, "%Y-%m-%d").strftime("%Y%m%d")
    except:
        pass
    logging.debug(' %s %s %s', was, day, selected_date)

    if was:
        logging.debug('SERVER: WAS Figure init ... ')
        fh = ForecastWasFigureHandler(was=was, selected_date=selected_date)
        logging.debug('SERVER: WAS Figure generation ... ')
        return fh.get_figure_layers(day=day)
    logging.debug('SERVER: NO WAS Figure')

    return ForecastWasFigureHandler().get_figure_layers()


def get_vis_figure(tstep=0, selected_date=END_DATE):
    """ Retrieve visibility figure layers

    Parameters
    ----------
    tstep : int, optional
        Timestep, by default 0
    selected_date : str, optional
        Selected date, by default END_DATE

    Returns
    -------
    list
        Figure layers
    """

    logging.debug(' %s %s', tstep, selected_date)
    try:
        selected_date = datetime.strptime(
            selected_date, "%Y-%m-%d").strftime("%Y%m%d")
    except:
        pass

    logging.debug(' %s %s', tstep, selected_date)

    if tstep is not None:
        logging.debug('SERVER: VIS Figure init ... ')
        fh = VisFigureHandler(selected_date=selected_date)
        logging.debug('SERVER: VIS Figure generation ... ')
        return fh.get_figure_layers(tstep=tstep)
    logging.debug('SERVER: NO VIS Figure')

    return VisFigureHandler().get_figure_layers()


def get_figure(selected_date=END_DATE, tstep=0, aspect=(1, 1), center=None, 
               selected_tiles='carto-positron', zoom=None, layers=None, index=None, tag='empty'):
    """ Generate map with figure layers

    Parameters
    ----------
    selected_date : str, optional
        Selected date, by default END_DATE
    tstep : int, optional
        Timestep, by default 0
    aspect : tuple, optional
        Map aspect, by default (1, 1)
    center : list, optional
        Map center, by default None
    selected_tiles : str, optional
        Map tiles, by default 'carto-positron'
    zoom : float, optional
        Map zoom, by default None
    layers : list, optional
        Figure layers, by default None
    index : str, optional
        Map index, by default None
    tag : str, optional
        Map tag, by default 'empty'

    Returns
    -------
    fig : dash_leaflet.Map
        Figure
    """

    logging.debug('***** SERVER: Figure generation: CURR_DATE %s TSTEP %s *****', selected_date, tstep)
    
    fh = MapHandler()
    return fh.retrieve_fig(aspect=aspect, center=center, selected_tiles= selected_tiles, 
                           zoom=zoom, tag=tag, index=index, layers=layers)
