"""Highest hourly values"""
from collections import OrderedDict
import datetime

import pandas as pd
from pandas.io.sql import read_sql
from matplotlib.font_manager import FontProperties
from pyiem.util import get_autoplot_context, get_dbconn
from pyiem.plot.use_agg import plt
from pyiem.exceptions import NoDataFound

PDICT = OrderedDict(
    [
        ("max_dwpf", "Highest Dew Point Temperature"),
        ("min_dwpf", "Lowest Dew Point Temperature"),
        ("max_tmpf", "Highest Air Temperature"),
        ("min_tmpf", "Lowest Air Temperature"),
        ("max_feel", "Highest Feels Like Temperature"),
        ("min_feel", "Lowest Feels Like Temperature"),
        ("max_mslp", "Maximum Sea Level Pressure"),
        ("min_mslp", "Minimum Sea Level Pressure"),
        ("max_alti", "Maximum Pressure Altimeter"),
        ("min_alti", "Minimum Pressure Altimeter"),
    ]
)
UNITS = {
    "max_dwpf": "F",
    "max_tmpf": "F",
    "min_dwpf": "F",
    "min_tmpf": "F",
    "min_feel": "F",
    "max_feel": "F",
    "max_mslp": "mb",
    "min_mslp": "mb",
    "max_alti": "in",
    "min_alti": "in",
}
MDICT = OrderedDict(
    [
        ("all", "No Month Limit"),
        ("spring", "Spring (MAM)"),
        ("fall", "Fall (SON)"),
        ("winter", "Winter (DJF)"),
        ("summer", "Summer (JJA)"),
        ("gs", "1 May to 30 Sep"),
        ("jan", "January"),
        ("feb", "February"),
        ("mar", "March"),
        ("apr", "April"),
        ("may", "May"),
        ("jun", "June"),
        ("jul", "July"),
        ("aug", "August"),
        ("sep", "September"),
        ("oct", "October"),
        ("nov", "November"),
        ("dec", "December"),
    ]
)


def get_description():
    """ Return a dict describing how to call this plotter """
    desc = dict()
    desc["data"] = True
    desc[
        "description"
    ] = """This table presents the extreme hourly value of
    some variable of your choice based on available observations maintained
    by the IEM.  Sadly, this app will likely point out some bad data points
    as such points tend to be obvious at extremes.  If you contact us to
    point out troubles, we'll certainly attempt to fix the archive to
    remove the bad data points.  Observations are arbitrarly bumped 10
    minutes into the future to place the near to top of the hour obs on
    that hour.  For example, a 9:53 AM observation becomes the ob for 10 AM.
    """
    desc["arguments"] = [
        dict(
            type="zstation",
            name="zstation",
            default="AMW",
            network="IA_ASOS",
            label="Select Station:",
        ),
        dict(
            type="select",
            name="month",
            default="all",
            options=MDICT,
            label="Select Month/Season/All",
        ),
        dict(
            type="select",
            name="var",
            options=PDICT,
            default="max_dwpf",
            label="Which Variable to Plot",
        ),
    ]
    return desc


def plotter(fdict):
    """ Go """
    font0 = FontProperties()
    font0.set_family("monospace")
    font0.set_size(16)
    font1 = FontProperties()
    font1.set_size(16)

    pgconn = get_dbconn("asos")
    ctx = get_autoplot_context(fdict, get_description())
    varname = ctx["var"]
    varname2 = varname.split("_")[1]
    if varname2 in ["dwpf", "tmpf", "feel"]:
        varname2 = "i" + varname2
    month = ctx["month"]
    station = ctx["zstation"]

    if month == "all":
        months = range(1, 13)
    elif month == "fall":
        months = [9, 10, 11]
    elif month == "winter":
        months = [12, 1, 2]
    elif month == "spring":
        months = [3, 4, 5]
    elif month == "summer":
        months = [6, 7, 8]
    elif month == "gs":
        months = [5, 6, 7, 8, 9]
    else:
        ts = datetime.datetime.strptime("2000-" + month + "-01", "%Y-%b-%d")
        # make sure it is length two for the trick below in SQL
        months = [ts.month]

    df = read_sql(
        f"""
    WITH obs as (
        SELECT (valid + '10 minutes'::interval) at time zone %s as ts,
        tmpf::int as itmpf, dwpf::int as idwpf,
        feel::int as ifeel, mslp, alti from alldata
        where station = %s and
        extract(month from valid at time zone %s) in %s),
    agg1 as (
        SELECT extract(hour from ts) as hr,
        max(idwpf) as max_dwpf,
        max(itmpf) as max_tmpf,
        min(idwpf) as min_dwpf,
        min(itmpf) as min_tmpf,
        min(ifeel) as min_feel,
        max(ifeel) as max_feel,
        max(alti) as max_alti,
        min(alti) as min_alti,
        max(mslp) as max_mslp,
        min(mslp) as min_mslp
        from obs GROUP by hr)
    SELECT o.ts, a.hr::int as hr,
        a.{varname} from agg1 a JOIN obs o on
        (a.hr = extract(hour from o.ts)
        and a.{varname} = o.{varname2})
        ORDER by a.hr ASC, o.ts DESC
    """,
        pgconn,
        params=(
            ctx["_nt"].sts[station]["tzname"],
            station,
            ctx["_nt"].sts[station]["tzname"],
            tuple(months),
        ),
        index_col=None,
    )
    if df.empty:
        raise NoDataFound("No Data was found.")
    y0 = 0.1
    yheight = 0.8
    dy = yheight / 24.0
    (fig, ax) = plt.subplots(1, 1, figsize=(8, 8))
    ax.set_position([0.12, y0, 0.57, yheight])
    ax.barh(df["hr"], df[varname], align="center")
    ax.set_ylim(-0.5, 23.5)
    ax.set_yticks([0, 4, 8, 12, 16, 20])
    ax.set_yticklabels(["Mid", "4 AM", "8 AM", "Noon", "4 PM", "8 PM"])
    ax.grid(True)
    ax.set_xlim([df[varname].min() - 5, df[varname].max() + 5])
    ax.set_ylabel(
        "Local Time %s" % (ctx["_nt"].sts[station]["tzname"],),
        fontproperties=font1,
    )

    ab = ctx["_nt"].sts[station]["archive_begin"]
    if ab is None:
        raise NoDataFound("Unknown station metadata")
    fig.text(
        0.5,
        0.93,
        ("%s [%s] %s-%s\n" "%s [%s]")
        % (
            ctx["_nt"].sts[station]["name"],
            station,
            ab.year,
            datetime.date.today().year,
            PDICT[varname],
            MDICT[month],
        ),
        ha="center",
        fontproperties=font1,
    )
    ypos = y0 + (dy / 2.0)
    for hr in range(24):
        sdf = df[df["hr"] == hr]
        if sdf.empty:
            continue
        row = sdf.iloc[0]
        fig.text(
            0.7,
            ypos,
            "%3.0f: %s%s"
            % (
                row[varname],
                pd.Timestamp(row["ts"]).strftime("%d %b %Y"),
                ("*" if len(sdf.index) > 1 else ""),
            ),
            fontproperties=font0,
            va="center",
        )
        ypos += dy
    ax.set_xlabel(
        "%s %s, * denotes ties" % (PDICT[varname], UNITS[varname]),
        fontproperties=font1,
    )

    return plt.gcf(), df


if __name__ == "__main__":
    plotter(dict())
