"""
Silique (https://www.silique.fr)
Copyright (C) 2022-2026

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

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
details.

You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""

from typing import Any, Optional

# from tiramisu import owners
from rougail.utils import undefined

from .i18n import _


class CommonOutput:

    def __init__(
        self,
        rougailconfig,
    ) -> None:
        self.set_config(rougailconfig)
        self.variable_default_enable = False
        self.variable_hidden_enable = False
        self.value_modified_enable = False
        self.value_unmodified_enable = False
        self.value_default_enable = False

    def set_config(self, rougailconfig):
        pass

    def run(self, nodes, layer_datas):
        self.layer_datas = layer_datas
        if nodes.children:
            root = self.parse(nodes)
            return self._run(root)
        return 0, ""

    def parse(self, node, parent=None, level=0):
        if node.hidden:
            self.variable_hidden_enable = True
            color = self.variable_hidden_color
        else:
            if node.hidden != None:
                self.variable_default_enable = True
            color = self.variable_normal_color
        family_output = self.colorize(
            [
                {
                    "value": node.description,
                    "color": color,
                    "loaded_from": None,
                }
            ]
        )
        subparent = self.get_parent(parent, family_output, level)
        for child in node.children:
            if child["type"] == "node":
                self.parse(child["node"], subparent, level + 1)
            else:
                if child["hidden"]:
                    self.variable_hidden_enable = True
                    variable_color = self.variable_hidden_color
                else:
                    self.variable_default_enable = True
                    variable_color = self.variable_normal_color
                if child["values"][0]["is_default"]:
                    self.value_unmodified_enable = True
                    color = self.value_unmodified_color
                else:
                    self.value_modified_enable = True
                    color = self.value_modified_color
                child["values"][0]["color"] = color
                if len(child["values"]) > 1:
                    self.value_default_enable = True
                value = self.colorize(
                    child["values"],
                )
                description = self.colorize(
                    [
                        {
                            "value": child["description"],
                            "color": variable_color,
                            "loaded_from": None,
                        }
                    ]
                )
                self.add_variable(
                    subparent, description, value, child["icon"], level + 1
                )
        return subparent

    def header(self):
        raise NotImplementedError()

    def error_warn_to_dict(self, error, errors_dict, level):
        if isinstance(error, dict):
            for msg, subconfig in error.items():
                description = subconfig.option.impl_get_display_name(subconfig)
                self.subconfig_to_dict(subconfig, errors_dict).setdefault(
                    None, {}
                ).setdefault(description, []).append((msg, level))
        else:
            errors_dict.setdefault(None, []).append(error)

    def subconfig_to_dict(self, subconfig: "Subconfig", errors_dict: dict) -> dict:
        # FIXME a tester : mandatories dans une arborescence (voir si ca n'ecrase pas)
        parents = []
        parent = subconfig
        while True:
            parent = parent.parent
            if parent is None:
                break
            parents.insert(0, parent)
        current_dict = errors_dict
        for child in parents[1:]:
            description = child.option.impl_get_display_name(child)
            current_dict = current_dict.setdefault(description, {})
        return current_dict

    def parse_error_warning(self, tree, error, display, default_color, level=0):
        self._parse_error_warning(tree, error, display, level, default_color)
        return self.display(tree)

    def _parse_error_warning(self, tree, error, display, level, default_color):
        if isinstance(error, list):
            for err in error:
                self._parse_error_warning(tree, err, display, level + 1, default_color)
        elif isinstance(error, dict):
            for key, value in error.items():
                if key is None:
                    # it's variables, no more families
                    self._parse_error_warning(
                        tree, value, display, level, default_color
                    )
                else:
                    if isinstance(value, list) and len(value) == 1:
                        self._parse_error_warning(
                            tree, (key, *value[0]), display, level + 1, default_color
                        )
                    else:
                        sub_tree = self._parse_error_warning(
                            tree, key, display, level + 1, default_color
                        )
                        self._parse_error_warning(
                            sub_tree, value, display, level + 1, default_color
                        )
        else:
            return display(level, tree, error, default_color)

    def warning_end(self):
        pass

    def add_family(
        self,
        family,
        level,
    ) -> "OutputFamily":
        properties = family.property.get()
        if "hidden" in properties:
            self.root_family.variable_hidden_enable = True
            color = self.variable_hidden_color
        else:
            self.root_family.variable_default_enable = True
            color = None
        family_output = self.colorize(
            [
                {
                    "value": family.description(),
                    "color": color,
                    "loaded_from": None,
                }
            ]
        )
        return self.__class__(
            family_output,
            self.get_tree(),
            self.root,
            level + 1,
            root_family=self.root_family,
        )

    def colorize(
        self,
        values,
        option=None,
    ) -> str:
        multi = False
        ret = []
        default = []
        empty_multi = False
        for idx, data in enumerate(values):
            value = data["value"]
            if isinstance(value, list):
                multi = True
                if not value:
                    empty_multi = True
                    value = ["[]"]
            else:
                value = [value]
            for vidx, val in enumerate(value):
                if len(ret) == vidx:
                    ret.append("")
                    default.append(False)
                if idx:
                    if not default[vidx]:
                        if ret[vidx]:
                            ret[vidx] += " "
                        ret[vidx] += "("
                        default[vidx] = True
                    else:
                        ret[vidx] += " "
                    ret[vidx] += ":hourglass_flowing_sand: "
                if option:
                    val = self.convert_value(
                        option,
                        val,
                    )
                color = data.get("color", self.value_default_color)
                ret[vidx] += self.set_color(color, val)
                loaded_from = data["loaded_from"]
                if loaded_from:
                    ret[vidx] += self.set_loaded(loaded_from)
        for idx in range(len(ret)):
            if default[idx]:
                ret[idx] += ")"
        if not multi or empty_multi:
            if not ret:
                return ""
            return ret[0]
        return ret

    def set_loaded(self, msg):
        return f" ◀ {msg}"

    def end(self):
        pass
