# -*- coding: utf-8 -*-
"""
/***************************************************************************
Name                 : Mascaret
Description          : Pre and Postprocessing for Mascaret for QGIS
Date                 : June,2017
copyright            : (C) 2017 by Artelia
email                :
***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/
"""

from datetime import timedelta

import matplotlib.dates as mdates
import matplotlib.ticker as ticker

from .GraphCommon import GraphCommon


class GraphHydroLaw(GraphCommon):
    """class Dialog GraphLaw"""

    def __init__(self, mgis=None, lay=None, typ_law=None):
        GraphCommon.__init__(self, mgis)
        self.mdb = self.mgis.mdb
        self.axes = None

        self.list_var = []
        self.list_z = []
        self.courbes = []
        self.old_xlim = None

        self.init_ui_common_p()
        self.gui_graph(lay)
        self.init_ui()

    def init_ui(self):
        """
        initialize GUI
        :return:
        """
        self.axes = self.fig.add_subplot(111)
        self.fig.canvas.mpl_connect("pick_event", self.onpick)
        self.fig.canvas.mpl_connect("draw_event", self.draw_event)
        self.axes.tick_params(axis="both", labelsize=7.0)
        self.axes.grid(True)

    def draw_event(self, event):
        """
        draw event
        :param event:
        :return:
        """
        if len(self.courbes) > 0:
            new_xlim = self.axes.get_xlim()
            if self.unit in ("date", "datehhmm"):
                if self.old_xlim == new_xlim:
                    return
                self.old_xlim = new_xlim
                xmin, xmax = new_xlim
                if (xmax - xmin) < 2:
                    self.maj_lbl_x("time", "datehhmm")
                else:
                    self.maj_lbl_x("time", "date")
                self.canvas.draw()

    def init_curv(self, typ_law=None, param_law=None, date_ref=None):
        """
        initialize curve
        :param typ_law: law type
        :param param_law: parameters law
        :param date_ref: reference date
        :return:
        """
        self.axes.cla()
        self.axes.tick_params(axis="both", labelsize=7.0)
        self.axes.grid(True)

        self.list_var.clear()
        self.list_z.clear()
        self.courbes.clear()

        if typ_law:
            self.axeX = param_law["graph"]["x"]["var"]
            for v, var in enumerate(param_law["graph"]["y"]["var"]):
                self.list_var.append({"id": var, "name": param_law["var"][var]["name"]})
                (self.courbe_laws,) = self.axes.plot(
                    [], [], zorder=100 - v, label=param_law["var"][var]["name"]
                )
                self.courbes.append(self.courbe_laws)

            self.init_legende()
            if date_ref:
                self.maj_lbl_x("time", "date")
            else:
                self.maj_lbl_x(param_law["graph"]["x"]["tit"], param_law["graph"]["x"]["unit"])
            self.maj_lbl_y(param_law["graph"]["y"]["tit"], param_law["graph"]["y"]["unit"])

        self.maj_limites()
        self.canvas.draw()

    def init_graph(self, id_law, date_ref=None, all_vis=False):
        """
        update law curve
        :param id_law: id law
        :param date_ref: reference date
        :param all_vis:  bool display all curve
        :return:
        """
        leglines = self.leg.get_lines()

        sql = (
            "SELECT value FROM {schema}.law_values WHERE id_law = %s "
            "AND id_var = %s ORDER BY id_order"
        )
        rows = self.mdb.run_query(sql, fetch=True, params=[id_law, self.axeX], schema=True)
        if date_ref:
            lst_x = [mdates.date2num(date_ref + timedelta(seconds=r[0])) for r in rows]
        else:
            lst_x = [r[0] for r in rows]

        for v, var in enumerate(self.list_var):
            lst_y = []
            if id_law is not None:
                sql = (
                    "SELECT value FROM {schema}.law_values "
                    "WHERE id_law = %s AND id_var = %s ORDER BY id_order"
                )
                rows = self.mdb.run_query(sql, fetch=True, params=[id_law, var["id"]], schema=True)
                if len(rows) > 0:
                    lst_y = [r[0] for r in rows]

            self.courbes[v].set_data(lst_x, lst_y)

            if all_vis:
                self.courbes[v].set_visible(True)
                leglines[v].set_alpha(1.0)

        self.maj_limites()

    def init_curv_weir_zam(self, param_law=None, id_law=None, var_x=0):
        """

        :param param_law: dict() parameter law
        :param id_law: id law
        :param var_x: varaible abscissa
        :return:
        """
        self.axes.cla()
        self.axes.tick_params(axis="both", labelsize=7.0)
        self.axes.grid(True)

        self.list_var.clear()
        self.list_z.clear()
        self.courbes.clear()
        self.axeX = var_x
        self.axeZ = abs(var_x - 1)

        if id_law:
            sql = (
                "SELECT DISTINCT value FROM {schema}.law_values "
                "WHERE id_law = %s AND id_var = %s ORDER BY value"
            )
            rows = self.mdb.run_query(sql, fetch=True, params=[id_law, self.axeZ], schema=True)
            self.list_z = [r[0] for r in rows]

            for idx, z in enumerate(self.list_z):
                name = "{0} {1} ({2})".format(
                    param_law["var"][self.axeZ]["leg"], idx + 1, round(z, 2)
                )
                self.list_var.append({"id": idx, "name": name})
                (self.courbe_laws,) = self.axes.plot([], [], zorder=100 - idx, label=name)
                self.courbes.append(self.courbe_laws)

            self.init_legende()

            if self.axeX == 0:
                self.maj_lbl_x("Q", "m3/s")
            elif self.axeX == 1:
                self.maj_lbl_x("Zdown", "m")
            self.maj_lbl_y(param_law["graph"]["y"]["tit"], param_law["graph"]["y"]["unit"])

        self.canvas.draw()

    def init_graph_weir_zam(self, id_law, all_vis=False):
        """
          update weir law curve
        :param id_law: id law
        :param all_vis:  bool display all curve
        :return:
        """
        leglines = self.leg.get_lines()

        lst_x_ref = None

        for idx, z in enumerate(self.list_z):
            sql = (
                "SELECT value FROM {schema}.law_values WHERE id_law = %s "
                "AND id_var = %s AND id_order IN "
                "(SELECT id_order FROM {schema}.law_values WHERE id_law = %s "
                "AND id_var = %s AND value = %s) "
                "ORDER BY id_order"
            )
            rows = self.mdb.run_query(
                sql,
                fetch=True,
                params=[id_law, self.axeX, id_law, self.axeZ, z],
                schema=True,
            )
            lst_x = [r[0] for r in rows]

            sql = (
                "SELECT value FROM {schema}.law_values WHERE id_law = %s "
                "AND id_var = 2 AND id_order IN "
                "(SELECT id_order FROM {schema}.law_values WHERE id_law = %s "
                "AND id_var = %s AND value = %s) "
                "ORDER BY id_order"
            )
            rows = self.mdb.run_query(
                sql,
                fetch=True,
                params=[id_law, id_law, self.axeZ, z],
                schema=True,
            )
            lst_y = [r[0] for r in rows]

            if not lst_x_ref:
                lst_x_ref = lst_x
            else:
                if lst_x_ref != lst_x:
                    break

            self.courbes[idx].set_data(lst_x, lst_y)

            if all_vis:
                self.courbes[idx].set_visible(True)
                leglines[idx].set_alpha(1.0)

        self.maj_limites()

    def init_graph_obs(self, data, param_law, all_vis=False):
        """
         update observation curve
        :param data: dict() data
        :param param_law: dict() law parameters
        :param all_vis: bool display all curve
        :return:
        """
        leglines = self.leg.get_lines()

        for v, var in enumerate(self.list_var):
            self.courbes[v].set_data(
                [mdates.date2num(date_) for date_ in data["date"]], data["val"]
            )

            if all_vis:
                self.courbes[v].set_visible(True)
                leglines[v].set_alpha(1.0)
        self.init_legende()
        self.maj_lbl_x("time", "date")

        self.maj_lbl_y(param_law["graph"]["y"]["tit"], param_law["graph"]["y"]["unit"])

        self.maj_limites()
        self.canvas.draw()

    def maj_lbl_x(self, var, unit):
        """
        Update x label
        :param var: variable
        :param unit:  unit
        :return:
        """
        self.unit = unit
        if unit in ("date", "datehhmm"):
            self.axes.set_xlabel("date")
        else:
            if unit:
                self.axes.set_xlabel("{} ({})".format(var, unit))
            else:
                self.axes.set_xlabel("{}".format(var))

        if unit == "date":
            self.axes.xaxis.set_major_formatter(mdates.DateFormatter("%d-%m-%Y"))
        elif unit == "datehhmm":
            self.axes.xaxis.set_major_formatter(mdates.DateFormatter("%d-%m-%Y %H:%M"))
        else:
            self.axes.xaxis.set_major_formatter(ticker.ScalarFormatter())

    def maj_lbl_y(self, var, unit):
        """
        Update y label
        :param var: variable
        :param unit:  unit
        :return:
        """
        if unit:
            self.axes.set_ylabel("{} ({})".format(var, unit))
        else:
            self.axes.set_ylabel("{}".format(var))

    def init_curv_assim(self, typ_law=None, param_law=None, date_ref=None):
        """
        initialize curve
        :param typ_law: law type
        :param param_law: parameters law
        :param date_ref: reference date
        :return:
        """
        self.axes.cla()
        self.axes.tick_params(axis="both", labelsize=7.0)
        self.axes.grid(True)

        self.list_var.clear()
        self.list_z.clear()
        self.courbes.clear()

        if typ_law:
            self.axeX = param_law["graph"]["x"]["var"]
            for v, var in enumerate(param_law["graph"]["y"]["var"]):
                self.list_var.append(
                    {"id": var, "name": f'Initial law -{param_law["var"][var]["name"]}'}
                )
                (courbe_laws,) = self.axes.plot(
                    [],
                    [],
                    linestyle="-",
                    zorder=100 - v * 2,
                    label=f'Initial law -{param_law["var"][var]["name"]}',
                    color="grey",
                )
                self.courbes.append(courbe_laws)
                self.list_var.append(
                    {"id": var, "name": f'New law - {param_law["var"][var]["name"]}'}
                )
                (courbe_ctrl,) = self.axes.plot(
                    [],
                    [],
                    linestyle="-",
                    color="blue",
                    label=f'New law - {param_law["var"][var]["name"]}',
                    zorder=100 - (v + 1) * 2,
                )
                self.courbes.append(courbe_ctrl)

            self.init_legende()
            if date_ref:
                self.maj_lbl_x("time", "date")
            else:
                self.maj_lbl_x(param_law["graph"]["x"]["tit"], param_law["graph"]["x"]["unit"])
            self.maj_lbl_y(param_law["graph"]["y"]["tit"], param_law["graph"]["y"]["unit"])

        self.maj_limites()
        self.canvas.draw()

    def init_graph_obs_assim(self, data, param_law, all_vis=False):
        """
        Update observation curves: raw result + controlled result
        :param data: dict {date, val, val_ctrl}
        :param param_law: dict, law parameters
        :param all_vis: bool, show all curve
        """
        dates = [mdates.date2num(d) for d in data["date"]]

        # Sécurité : vérifier que 2 courbes sont bien présentes
        if len(self.courbes) < 2:
            print("[ ERROR ] Erreur : init_graph_obs attend 2 courbes (brut + ctrl).")
            return

        # --- Courbe 1 : resultat brut ---
        self.courbes[0].set_data(dates, data["val"])

        # --- Courbe 2 : resultat controlé ---
        self.courbes[1].set_data(dates, data.get("val_ctrl", []))

        # Visibilité si nécessaire
        if all_vis:
            for i, curve in enumerate(self.courbes):
                curve.set_visible(True)
                legline = self.leg.get_lines()[i]
                legline.set_alpha(1.0)

        # Mise à jour de la légende
        self.init_legende()

        # Labels axes
        self.maj_lbl_x("time", "date")
        self.maj_lbl_y(param_law["graph"]["y"]["tit"], param_law["graph"]["y"]["unit"])

        # Limites auto
        self.maj_limites()

        # Rafraîchissement
        self.canvas.draw()

    def init_graph_assim(self, id_law, date_ref=None, all_vis=False):
        """
        update law curve
        :param id_law: id law
        :param date_ref: reference date
        :param all_vis:  bool display all curve
        :return:
        """
        leglines = self.leg.get_lines()

        sql = (
            "SELECT value FROM {schema}.law_values WHERE "
            "id_law = %s AND id_var = %s ORDER BY id_order"
        )
        rows = self.mdb.run_query(sql, fetch=True, params=[id_law, self.axeX], schema=True)
        if date_ref:
            lst_x = [mdates.date2num(date_ref + timedelta(seconds=r[0])) for r in rows]
        else:
            lst_x = [r[0] for r in rows]

        for v, var in enumerate(self.list_var):
            lst_y = []
            if id_law is not None:
                sql = (
                    "SELECT value FROM {schema}.law_values "
                    "WHERE id_law = %s AND id_var = %s ORDER BY id_order"
                )
                rows = self.mdb.run_query(sql, fetch=True, params=[id_law, var["id"]], schema=True)
                if len(rows) > 0:
                    lst_y = [r[0] for r in rows]

            self.courbes[v].set_data(lst_x, lst_y)

            if all_vis:
                self.courbes[v].set_visible(True)
                leglines[v].set_alpha(1.0)

        self.maj_limites()
