# Copyright 2017-20 ForgeFlow S.L. (https://www.forgeflow.com)
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).

import json
import logging
from math import pi

from odoo import _, fields, models

_logger = logging.getLogger(__name__)
try:
    import numpy as np
    import pandas as pd
    from bokeh.embed import components
    from bokeh.models import DatetimeTickFormatter, HoverTool
    from bokeh.plotting import figure
except (ImportError, IOError) as err:
    _logger.debug(err)


class StockBuffer(models.Model):
    _inherit = "stock.buffer"

    planning_history_chart = fields.Text(
        string="Historical Chart",
        compute="_compute_history_chart",
    )
    execution_history_chart = fields.Text(
        string="Execution Historical Chart",
        compute="_compute_execution_history_chart",
    )

    def _prepare_history_data(self):
        self.ensure_one()
        data = {
            "buffer_id": self.id,
            "date": fields.Datetime.now(),
            "top_of_red": self.top_of_red,
            "top_of_yellow": self.top_of_yellow,
            "top_of_green": self.top_of_green,
            "net_flow_position": self.net_flow_position,
            "on_hand_position": self.product_location_qty_available_not_res,
            "adu": self.adu,
        }
        return data

    def cron_actions(self, only_nfp=False):
        res = super().cron_actions(only_nfp=only_nfp)
        data = self._prepare_history_data()
        if not self.env.context.get("no_ddmrp_history"):
            self.env["ddmrp.history"].sudo().create(data)
        return res

    def _compute_history_chart(self):
        def stacked(df, categories):
            areas = {}
            last = np.zeros(len(df[categories[0]]))
            for cat in categories:
                _next = last + df[cat]
                areas[cat] = np.hstack((last[::-1], _next))
                last = _next
            return areas

        hex_colors = self._get_colors_hex_map(pallete="planning")
        planning_colors = [
            hex_colors["1_red"],
            hex_colors["2_yellow"],
            hex_colors["3_green"],
        ]
        for rec in self:
            history = self.env["ddmrp.history"].search(
                [("buffer_id", "=", rec.id)], order="date"
            )
            if len(history) < 2:
                rec.planning_history_chart = json.dumps(
                    {
                        "div": _("Not enough data available."),
                        "script": "",
                    }
                )
                continue

            N = len(history)
            categories = ["top_of_red", "top_of_yellow", "top_of_green"]
            data = {}

            dates = [r.date for r in history]
            data["date"] = dates
            data[categories[0]] = [r.top_of_red for r in history]
            data[categories[1]] = [r.top_of_yellow - r.top_of_red for r in history]
            data[categories[2]] = [r.top_of_green - r.top_of_yellow for r in history]
            data["net_flow_position"] = [r.net_flow_position for r in history]
            data["on_hand_position"] = [r.on_hand_position for r in history]

            df = pd.DataFrame(data)
            df = df.set_index(["date"])

            areas = stacked(df, categories)

            x2 = np.hstack((data["date"][::-1], data["date"]))

            tops = [
                data[categories[0]][i] + data[categories[1]][i] + data[categories[2]][i]
                for i in range(N)
            ] + [max(data["on_hand_position"]), max(data["net_flow_position"])]
            top_y = max(tops)
            min_y = min(
                [0, min(data["on_hand_position"]), min(data["net_flow_position"])]
            )
            if top_y <= min_y:
                top_y = min_y + 100
            p = figure(
                frame_height=400,
                x_range=(dates[0], dates[-1]),
                y_range=(min_y, top_y),
                x_axis_type="datetime",
            )
            p.sizing_mode = "stretch_width"
            p.toolbar.logo = None

            p.grid.minor_grid_line_color = "#eeeeee"
            p.patches(
                [x2] * len(areas),
                [areas[cat] for cat in categories],
                color=planning_colors,
                alpha=0.8,
                line_color=None,
            )
            date_format = (
                self.env["res.lang"]._lang_get(self.env.lang or "en_US").date_format
            )
            p.xaxis.formatter = DatetimeTickFormatter(
                hours=date_format,
                days=date_format,
                months=date_format,
                years=date_format,
            )
            p.xaxis.major_label_orientation = pi / 4
            p.xaxis.axis_label_text_font = "helvetica"

            unit = rec.product_uom.name
            hover = HoverTool(
                tooltips=[("qty", "$y %s" % unit)], point_policy="follow_mouse"
            )
            p.add_tools(hover)

            p.line(dates, data["net_flow_position"], line_width=3)
            p.line(dates, data["on_hand_position"], line_width=3, line_dash="dotted")

            script, div = components(p, wrap_script=False)
            json_data = json.dumps(
                {
                    "div": div,
                    "script": script,
                }
            )
            rec.planning_history_chart = json_data

    def _compute_execution_history_chart(self):
        start_stack = 0

        def stacked(df, categories):
            areas = {}
            last = np.zeros(len(df[categories[0]]))
            last += start_stack
            for cat in categories:
                _next = last + df[cat]
                areas[cat] = np.hstack((last[::-1], _next))
                last = _next
            return areas

        hex_colors = self._get_colors_hex_map(pallete="execution")
        execution_colors = [
            hex_colors["0_dark_red"],
            hex_colors["1_red"],
            hex_colors["2_yellow"],
            hex_colors["3_green"],
            hex_colors["2_yellow"],
            hex_colors["1_red"],
            hex_colors["0_dark_red"],
        ]
        history_model = self.env["ddmrp.history"]
        for rec in self:
            domain = [("buffer_id", "=", rec.id)]
            history_oh = history_model.search(
                domain, order="on_hand_position desc", limit=1
            )
            history_tog = history_model.search(
                domain + [("top_of_green", "!=", False)],
                order="top_of_green desc",
                limit=1,
            )
            finish_stack = max(history_oh.on_hand_position, history_tog.top_of_green)

            history = history_model.search(
                domain, order="on_hand_position asc", limit=1
            )
            start_stack = history.on_hand_position
            if start_stack >= 0.0:
                start_stack = 0.0
            history = history_model.search(domain, order="date")
            if len(history) < 2:
                rec.execution_history_chart = json.dumps(
                    {
                        "div": _("Not enough data available."),
                        "script": "",
                    }
                )
                continue

            N = len(history)

            categories = [
                "dark_red_low",
                "top_of_red_low",
                "top_of_yellow_low",
                "top_of_green",
                "top_of_yellow",
                "top_of_red",
                "dark_red",
            ]
            data = {}

            dates = [r.date for r in history]
            data["date"] = dates
            data[categories[0]] = [(0 - start_stack) for r in history]
            data[categories[1]] = [(r.top_of_red / 2) for r in history]
            data[categories[2]] = [(r.top_of_red / 2) for r in history]
            data[categories[3]] = [r.top_of_green - r.top_of_yellow for r in history]
            data[categories[4]] = [
                (r.top_of_green - r.top_of_red - (r.top_of_green - r.top_of_yellow)) / 2
                for r in history
            ]
            data[categories[5]] = [
                (r.top_of_green - r.top_of_red - (r.top_of_green - r.top_of_yellow)) / 2
                for r in history
            ]
            data[categories[6]] = [
                finish_stack
                - r.top_of_red
                - (r.top_of_green - r.top_of_yellow)
                - (r.top_of_green - r.top_of_red - (r.top_of_green - r.top_of_yellow))
                for r in history
            ]

            data["on_hand_position"] = [r.on_hand_position for r in history]

            df = pd.DataFrame(data)
            df = df.set_index(["date"])

            areas = stacked(df, categories)

            x2 = np.hstack((data["date"][::-1], data["date"]))

            tops = [
                data[categories[0]][i]
                + data[categories[1]][i]
                + data[categories[2]][i]
                + data[categories[3]][i]
                + data[categories[4]][i]
                + data[categories[5]][i]
                + data[categories[6]][i]
                for i in range(N)
            ]
            top_y = max(tops)
            p = figure(
                frame_height=400,
                x_range=(dates[0], dates[-1]),
                y_range=(start_stack, top_y or 100),
                x_axis_type="datetime",
            )
            p.sizing_mode = "stretch_width"
            p.toolbar.logo = None

            p.grid.minor_grid_line_color = "#eeeeee"
            p.patches(
                [x2] * len(areas),
                [areas[cat] for cat in categories],
                color=execution_colors,
                alpha=0.8,
                line_color=None,
            )
            date_format = (
                self.env["res.lang"]._lang_get(self.env.lang or "en_US").date_format
            )
            p.xaxis.formatter = DatetimeTickFormatter(
                hours=date_format,
                days=date_format,
                months=date_format,
                years=date_format,
            )
            p.xaxis.major_label_orientation = pi / 4

            unit = rec.product_uom.name
            hover = HoverTool(
                tooltips=[("qty", "$y %s" % unit)], point_policy="follow_mouse"
            )
            p.add_tools(hover)

            p.line(dates, data["on_hand_position"], line_width=3, line_dash="dotted")

            script, div = components(p, wrap_script=False)
            json_data = json.dumps(
                {
                    "div": div,
                    "script": script,
                }
            )
            rec.execution_history_chart = json_data
