"""
Silique (https://www.silique.fr)
Copyright (C) 2025
            
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 pathlib import Path
from json import loads
from .config import OutPuts
from .i18n import _
from .utils import calc_path


class Changelog:  # pylint: disable=no-member,too-few-public-methods
    """Build changelog"""

    def gen_doc_changelog(self):
        """Return changelog"""
        self.level = self.rougailconfig["doc.title_level"]
        self.previous_json_file = self.rougailconfig["doc.previous_json_file"]
        with Path(self.previous_json_file).open() as outfh:
            previous_doc = loads(outfh.read())
        self.load()
        self._added_variables = []
        self._modified_variables = []
        self._removed_variables = []
        root = self.rougailconfig["doc.root"]
        if root:
            informations = self.informations
            for family in root.split('.'):
                informations = informations[family]["children"]
                if previous_doc and family in previous_doc:
                    previous_doc = previous_doc[family]['children']
                else:
                    previous_doc = {}
        else:
            informations = self.informations
        self.formatter.options()
        self.parser(previous_doc, informations)
        return self.display()

    def parser(self, previous_families, new_families):
        done = []
        for element in list(previous_families) + list(new_families):
            if element in done:
                continue
            done.append(element)
            previous = previous_families.get(element)
            new = new_families.get(element)
            if not previous:
                if new["type"] == "variable":
                    self._added_variables.append(new)
                else:
                    self.parser({}, new["children"])
            elif not new:
                if previous["type"] == "variable":
                    if "identifiers" in previous:
                        for identifiers in previous["identifiers"]:
                            self._removed_variables.append(calc_path(previous["path"], self.formatter, identifiers))
                    else:
                        self._removed_variables.append(calc_path(previous["path"], self.formatter))
                else:
                    self.parser(previous["children"], {})
            elif previous["type"] != new["type"]:
                if previous["type"] == "variable":
                    if "identifiers" in previous:
                        for identifiers in previous["identifiers"]:
                            self._removed_variables.append(calc_path(previous["path"], self.formatter, identifiers))
                    else:
                        self._removed_variables.append(calc_path(previous["path"], self.formatter))
                    self.parser({}, new["children"])
                else:
                    self._added_variables.append(new)
                    self.parser(previous["children"], {})
            elif previous["type"] != "variable":
                self.parser(previous["children"], new["children"])
            else:
                modified_attributes = {}
                for prop in set(previous) | set(new):
                    prop_previous = previous.get(prop, [])
                    prop_new = new.get(prop, [])
                    if prop_previous != prop_new:
                        name = None
                        if (
                            isinstance(prop_previous, dict)
                            and "values" in prop_previous
                        ):
                            name = prop_previous["name"]
                            local_prop_previous = prop_previous = prop_previous[
                                "values"
                            ]
                            if not isinstance(prop_previous, list):
                                if prop == "default":
                                    local_prop_previous = [prop_previous]
                                else:
                                    local_prop_previous = prop_previous = [
                                        prop_previous
                                    ]
                        elif isinstance(prop_previous, list):
                            local_prop_previous = prop_previous
                        else:
                            local_prop_previous = [prop_previous]
                        if isinstance(prop_new, dict) and "values" in prop_new:
                            name = prop_new["name"]
                            prop_new = prop_new["values"]
                            if not isinstance(prop_new, list):
                                prop_new = [prop_new]
                        if isinstance(prop_new, list):
                            prop_new = prop_new.copy()
                        else:
                            prop_new = [prop_new]
                        if isinstance(prop_previous, list):
                            prop_previous = [
                                p for p in prop_previous if p not in prop_new
                            ]
                        elif prop_previous in prop_new:
                            prop_new.remove(prop_previous)
                            prop_previous = []
                        else:
                            prop_previous = [prop_previous]
                        prop_new = [p for p in prop_new if p not in local_prop_previous]
                        if prop_previous not in [None, []] or prop_new not in [
                            None,
                            [],
                        ]:
                            modified_attributes[prop] = (name, prop_previous, prop_new)
                if not modified_attributes:
                    continue
                self._modified_variables.append((new, modified_attributes))

    def display(self) -> str:
        msg = ""
        if self._added_variables:
            if len(self._added_variables) == 1:
                title = _("New variable")
            else:
                title = _("New variables")
            for add in self._added_variables:
                self.formatter.variable_to_string(add)
            msg += self.formatter._run(
                [
                    self.formatter.title(title, self.level),
                    self.formatter.table(),
                    self.formatter.end_family(self.level)
                ],
                self.level,
                dico_is_already_treated=True,
            )
        if self._modified_variables:
            if len(self._modified_variables) == 1:
                title = _("Modified variable")
            else:
                title = _("Modified variables")
            for mod, modified_attributes in self._modified_variables:
                self.formatter.variable_to_string(mod, modified_attributes)
            msg += self.formatter._run(
                [
                    self.formatter.title(title, self.level),
                    self.formatter.table(),
                    self.formatter.end_family(self.level)
                ],
                self.level,
                dico_is_already_treated=True,
            )
        if self._removed_variables:
            if len(self._removed_variables) == 1:
                title = _("Deleted variable")
            else:
                title = _("Deleted variables")
            msg += self.formatter._run(
                [
                    self.formatter.title(title, self.level),
                    self.formatter.list(self._removed_variables, inside_table=False),
                    self.formatter.end_family(self.level)
                ],
                self.level,
                dico_is_already_treated=True,
            )
        return msg
