#!/usr/bin/env python
# -*- coding: utf-8 -*-.
# Full license can be found in License.md
# Full author list can be found in .zenodo.json file
# DOI:10.5281/zenodo.3986138
# ----------------------------------------------------------------------------
"""Provides support functions for the LASP LISIRD data base."""

import datetime as dt
import json
import numpy as np
import os
import pandas as pds
import requests

import pysat

ackn = "".join(["LASP Interactive Solar Irradiance Data Center provides ",
                "access to many solar datasets generated by researchers at ",
                "LASP and other institutions."])


def references(platform, name, tag, inst_id):
    """Provide references for different Instrument data products.

    Parameters
    ----------
    platform : str
        Instrument platform
    name : str
        Instrument name
    tag : str
        Instrument tag
    inst_id : str
        Instrument ID

    Returns
    -------
    refs : str
        String of references

    """

    refs = {'sw': {'mgii': {
        'composite': {
            '': ''.join(["Viereck, R. A., Floyd, L. E., Crane, P. C., Woods, ",
                         "T. N., Knapp, B. G., Rottman, G., Weber, M., Puga,",
                         " L. C., and DeLand, M. T. (2004), A composite Mg ",
                         "II index spanning from 1978 to 2003, Space Weather",
                         ", 2, S10005, doi:10.1029/2004SW000084."])},
        'sorce': {
            '': "\n".join([
                "".join(["Snow, M, William E. McClintock, Thomas N. Woods, ",
                         "Oran R. White, Jerald W. Harder, and Gary Rottman ",
                         "(2005). The Mg II Index from SORCE, Solar Phys., ",
                         "230, 1, 325-344."]),
                "".join(["Heath, D. and Schlesinger, B. (1986). The Mg 280-nm ",
                         "doublet as a monitor of changes in solar ",
                         "ultraviolet irradiance, JGR, 91, 8672-8682."])])}}}}

    return refs[platform][name][tag][inst_id]


def build_lisird_url(lisird_data_name, start, stop):
    """Build a LASP LISIRD direct download URL.

    Parameters
    ----------
    lisird_data_name : str
        Name of the data set on the LISARD server
    start : dt.datetime
        Start time
    stop : dt.datetime
        Stop time

    Returns
    -------
    url : str
        URL that will download the desired data

    """

    # Define the formatting for the start and stop times
    tfmt = "%Y-%m-%dT%H:%M:%S.000Z"

    url = "".join(["https://lasp.colorado.edu/lisird/latis/dap/",
                   lisird_data_name, ".json?&time>=", start.strftime(tfmt),
                   '&time<=', stop.strftime(tfmt),
                   "&format_time(yyyy-MM-dd'T'HH:mm:ss.SSS)"])

    return url


def download(date_array, data_path, local_file_prefix, local_date_fmt,
             lisird_data_name, freq, update_files=True, fill_vals=None):
    """Download routine for LISIRD data.

    Parameters
    ----------
    date_array : array-like
        Sequence of dates for which files will be downloaded.
    data_path : str
        Path to data directory.
    local_file_prefix : str
        Prefix for local files, e.g., 'tag_' or 'tag_monthly_'
    local_date_fmt : str
        String format for the local filename, e.g., '%Y-%m-%d' or '%Y-%m'
    lisird_data_name : str
        Name of the data set on the LISARD server
    freq : pds.DateOffset or dt.timedelta
        Offset to add to the start date to ensure all data is downloaded
        (inclusive)
    update_files : bool
        Re-download data for files that already exist if True (default=False)
    fill_vals : dict or NoneType
        Dict of fill values to replace with NaN by variable name or None to
        leave alone

    Raises
    ------
    IOError
        If there is a gateway timeout when downloading data
    KeyError
        If the `fill_vals` input does not match the downloaded data

    """
    # Initialize the fill_vals dict, if necessary
    if fill_vals is None:
        fill_vals = {}

    # Cycle through all the dates
    for dl_date in date_array:
        # Build the local filename
        local_file = os.path.join(
            data_path, ''.join([local_file_prefix,
                                dl_date.strftime(local_date_fmt), '.txt']))

        # Determine if the download should occur
        if update_files or not os.path.isfile(local_file):
            # Get the URL for the desired data
            url = build_lisird_url(lisird_data_name, dl_date, dl_date + freq)

            # The data is returned as a JSON file
            req = requests.get(url)

            # Process the JSON file
            if req.text.find('Gateway Timeout') >= 0:
                raise IOError(''.join(['Gateway timeout when requesting ',
                                       'file using command: ', url]))

            if req.ok:
                raw_dict = json.loads(req.text)[lisird_data_name]
                data = pds.DataFrame.from_dict(raw_dict['samples'])
                if data.empty:
                    pysat.logger.warning("no data for {:}".format(dl_date))
                else:
                    # The URL specifies the time format, so break it down
                    frac_sec = [int(tval.split('.')[-1])
                                for tval in data['time']]
                    times = [dt.datetime.strptime(tval.split('.')[0],
                                                  '%Y-%m-%dT%H:%M:%S')
                             + dt.timedelta(microseconds=frac_sec[i] * 6)
                             for i, tval in enumerate(data.pop('time'))]
                    data.index = times

                    # Replace fill value with NaNs
                    for var in fill_vals.keys():
                        if var in data.columns:
                            idx, = np.where(data[var] == fill_vals[var])
                            data.iloc[idx, :] = np.nan
                        else:
                            raise KeyError(''.join(['unknown fill value ',
                                                    'variable name supplied: ',
                                                    var]))

                    # Create a local CSV file
                    data.to_csv(local_file, header=True)
            else:
                pysat.logger.info("".join(["Data not downloaded for ",
                                           dl_date.strftime("%d %b %Y"),
                                           ", date may be out of range ",
                                           "for the database."]))
    return
