#
# Copyright (c) Daniel Sheffield 2023
#
# All rights reserved
#
# THIS SOFTWARE IS PROVIDED AS IS WITHOUT WARRANTY
from io import StringIO
from queue import Queue
from bottle import (
    FormsDict,
    HTTPError,
    template,
)
import matplotlib.pyplot as plt
import matplotlib
import seaborn as sns
from psycopg import Connection
from psycopg.connection import TupleRow

from . import ALL_UNITS, BOOLEAN, PARAMS
from ..data.QueryManager import (
    display_mapper,
    QueryManager,
)
from ..data.filter import (
    get_filter,
    get_query_param,
)
from ..activities.Plot import (
    get_data,
)
from .form import(
    get_form,
)

matplotlib.use('agg')

def abort(code, text):
    return HTTPError(code, text)

def trend(queue: Queue, conn: Connection[TupleRow], path: str, query: FormsDict):
    for item in trend_internal(conn, path, query):
        queue.put(item, block=True)
    queue.put(None)

def trend_internal(conn: Connection[TupleRow], path: str, query: FormsDict):
    progress = []
    try:
        with conn.cursor() as cur:
            query_manager = QueryManager(cur, display_mapper)
            _filter = get_filter(query, allow=PARAMS)
            fields = {
                k: get_query_param(*_filter[k])
                for k in sorted(_filter) if k not in ('organic', 'unit') and _filter[k]
            }
            unit = fields['unit'] = fields['unit'] or 'kg' if 'unit' in fields else 'kg'
            fields['organic'] = BOOLEAN.get(query.organic, None)
            if unit and unit not in ALL_UNITS:
                yield abort(400, f"Unsupported unit {unit}")
                return

            progress.append({ "name": "Loading data", "status": ""})
            yield template("loading", progress=progress)
            data = get_data(query_manager, **fields)
            progress[-1]["status"] = "done"
            yield template("loading", progress=progress)

            if data.empty:
                yield abort(404, f"No data for {fields}")
                return
            
            in_chart = data['$/unit'].apply(lambda x: (x or False) and True)
            data = data[in_chart]
            
            progress.append({ "name": "Loading chart", "status": ""})
            yield template("loading", progress=progress)
            
            pivot = data.pivot_table(index=['ts_raw',], columns=['product',], values=['$/unit'], aggfunc='mean')
            pivot.columns = pivot.columns.droplevel()
            sns.set_theme(style='darkgrid', palette='pastel', context="talk")
            plt.style.use("dark_background")
            plt.rcParams.update({
    "lines.color": "#ffffff",
    "patch.edgecolor": "#ffffff",
    "text.color": "#ffffff",
    "axes.facecolor": "#7f7f7f",
    "axes.edgecolor": "#ffffff",
    "axes.labelcolor": "#ffffff",
    "xtick.color": "#ffffff",
    "ytick.color": "#ffffff",
    "grid.color": "#ffffff",
    "figure.facecolor": "#7f7f7f",
    "figure.edgecolor": "#7f7f7f",
    "savefig.facecolor": "#7f7f7f",
    "savefig.edgecolor": "#7f7f7f"})
            plt.rcParams.update({"grid.linewidth":0.2, "grid.alpha":0.5})
            plt.figure(figsize=[16, 9], layout="tight")
            xlabel='Time'
            ylabel=f'$ / {unit}'
            if pivot.columns.size > 50:
                ax = sns.scatterplot(data=pivot, markers=True)
            else:
                ax = sns.lineplot(data=pivot, markers=True)
                legend = plt.figlegend(
                    loc='upper center', ncol=6,
                    title_fontsize="14", fontsize="12", labelcolor='#ffffff',
                    framealpha=0.5
                )
                legend.set_title(title="Products")
            ax.legend().set_visible(False)

            ax.set_xlabel(xlabel, fontsize="14")
            ax.set_ylabel(ylabel, fontsize="14")
            ax.axes.tick_params(labelsize="12", which='both')
            for _, spine in ax.spines.items():
                spine.set_color('#ffffff')
            
            progress[-1]["status"] = "done"
            yield template("loading", progress=progress)
            
            progress.append({ "name": "Rendering chart", "status": ""})
            yield template("loading", progress=progress)

            f = StringIO()
            plt.savefig(f, format='svg')
            organic = BOOLEAN.get(query.organic, None)
            action = path.split('/')[-1]
            form = get_form(action, 'post', _filter, organic, data)
            
            progress[-1]["status"] = "done"
            yield template("loading", progress=progress)
            
            yield template("trend", form=form, svg=f.getvalue())

    finally:
        conn.commit()
