"""
Silique (https://www.silique.fr)
Copyright (C) 2024-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 Optional
from ruamel.yaml import CommentedMap
from ruamel.yaml.representer import RoundTripRepresenter


from .utils import _, calc_path, dump


# XXX explicit null (see rougail-output-formatter
def represent_none(self, data):
    return self.represent_scalar("tag:yaml.org,2002:null", "null")


def represent_str(self, data):
    if data == "":
        return self.represent_scalar("tag:yaml.org,2002:null", "")
    return self.represent_scalar("tag:yaml.org,2002:str", data)


RoundTripRepresenter.add_representer(type(None), represent_none)
RoundTripRepresenter.add_representer(str, represent_str)
# XXX


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

    def __init__(self):
        self.examples = None
        self.examples_mandatories = None

    def gen_doc_examples(self):
        """Return examples"""
        self.comment_examples = self.rougailconfig["doc.examples.comment"]
        self.level = self.rougailconfig["doc.title_level"]
        if self.comment_examples:
            self.comment_examples_column = self.rougailconfig["doc.examples.comment_column"]
        self._build_examples()
        return_string = ""
        datas = []
        if self.examples_mandatories:
            if self.document_a_type:
                col = list(self.examples_mandatories)
                if len(col) == 1:
                    examples_mandatories = self.examples_mandatories[col[0]]
                else:
                    examples_mandatories = self.examples_mandatories
            else:
                examples_mandatories = self.examples_mandatories
            datas.extend([
                self.formatter.title(
                    _("Example with mandatory variables not filled in"), self.level
                ),
                self.formatter.yaml(dump(examples_mandatories)),
                self.formatter.end_family(self.level),
                ])
        if self.examples:
            if self.document_a_type:
                col = list(self.examples)
                if len(col) == 1:
                    examples = self.examples[col[0]]
                else:
                    examples = self.examples
            else:
                examples = self.examples
            datas.extend([self.formatter.title(
                            _("Example with all variables modifiable"), self.level
                          ),
                          self.formatter.yaml(dump(examples)),
                          self.formatter.end_family(self.level),
                          ])
        return self.formatter.compute(datas)

    def _build_examples(self):
        examples, examples_mandatories = self._parse_examples(
            self.informations
        )
        self.examples = examples
        self.examples_mandatories = examples_mandatories

    def _parse_examples(self, dico, dyn_parent: Optional[str] = None) -> tuple:
        if self.comment_examples:
            examples = CommentedMap()
            examples_mandatories = CommentedMap()
        else:
            examples = {}
            examples_mandatories = {}
        for value in dico.values():
            if value["type"] == "variable":
                parse = self._parse_examples_variable
            else:
                parse = self._parse_examples_family
            parse(
                value, dyn_parent, examples, examples_mandatories
            )
        return examples, examples_mandatories

    def _parse_examples_variable(
        self,
        variable,
        dyn_parent: Optional[str],
        examples: dict,
        examples_mandatories: dict,
    ) -> None:
        paths = []
        ori_path = variable["path"]
        if "identifiers" in variable:
            for idx, identifiers in enumerate(variable["identifiers"]):
                paths.append(calc_path(ori_path, identifiers=identifiers))
        else:
            paths.append(ori_path)
        for idx, path in enumerate(paths):
            path = calc_path(path)
            if dyn_parent is not None and not path.startswith(dyn_parent):
                continue
            if len(variable["names"]) == 1:
                name = variable["names"][0]
            else:
                name = variable["names"][idx]
            value = variable["gen_examples"][idx]
            examples[name] = value
            if self.comment_examples and "description" in variable:
                description = variable["description"]
                if description.endswith('.'):
                    description = description[:-1]
                examples.yaml_add_eol_comment(description, name, column=self.comment_examples_column)
            if variable["mandatory_without_value"]:
                examples_mandatories[name] = value
                if self.comment_examples and "description" in variable:
                    description = variable["description"]
                    if description.endswith('.'):
                        description = description[:-1]
                    examples_mandatories.yaml_add_eol_comment(description, name, column=self.comment_examples_column)
            break

    def _parse_examples_family(
        self,
        family,
        dyn_parent: Optional[str],
        examples: dict,
        examples_mandatories: dict,
    ) -> None:
        def _set_example(idx, identifiers):
            path = calc_path(ori_path, identifiers=identifiers)
            if dyn_parent is not None and not path.startswith(dyn_parent):
                return
            if len(family["informations"]["names"]) == 1:
                name = family["informations"]["names"][0]
            else:
                name = family["informations"]["names"][idx]
            if family["type"] == "leadership":
                func = self._parse_examples_leadership
            else:
                func = self._parse_examples
            ret_e, ret_m = func(
                family["children"],
                path + "." if family["type"] == "dynamic" else dyn_parent,
            )
            if ret_m:
                examples_mandatories[name] = ret_m
                if self.comment_examples and "description" in family["informations"]:
                    description = family["informations"]["description"]
                    if description.endswith('.'):
                        description = description[:-1]
                    examples_mandatories.yaml_add_eol_comment(description, name, column=self.comment_examples_column)
            if ret_e:
                examples[name] = ret_e
                if self.comment_examples and "description" in family["informations"]:
                    description = family["informations"]["description"]
                    if description.endswith('.'):
                        description = description[:-1]
                    examples.yaml_add_eol_comment(description, name, column=self.comment_examples_column)

        ori_path = family["informations"]["path"]
        if "identifiers" in family["informations"]:
            for idx, identifiers in enumerate(family["informations"]["identifiers"]):
                _set_example(idx, identifiers)
        else:
            _set_example(0, None)

    def _parse_examples_leadership(
        self, leadership, dyn_parent: Optional[str] = None
    ) -> tuple:
        examples = []
        examples_mandatories = []
        leader = next(iter(leadership.values()))
        paths = []
        ori_path = leader["path"]
        if "identifiers" in leader:
            for idx, identifiers in enumerate(leader["identifiers"]):
                paths.append(calc_path(ori_path, identifiers=identifiers))
        else:
            paths.append(ori_path)
        for path_idx, path in enumerate(paths):
            path = calc_path(path)
            if dyn_parent is not None and not path.startswith(dyn_parent):
                continue
            for leader_idx in range(len(leader["gen_examples"][path_idx])):
                if self.comment_examples:
                    followers = CommentedMap()
                else:
                    followers = {}
                for follower in leadership.values():
                    if len(follower["names"]) == 1:
                        name = follower["names"][0]
                    else:
                        name = follower["names"][path_idx]
                    followers[name] = follower["gen_examples"][path_idx][leader_idx]
                    if self.comment_examples and "description" in follower:
                        description = follower["description"]
                        if description.endswith('.'):
                            description = description[:-1]
                        followers.yaml_add_eol_comment(description, name, column=self.comment_examples_column)
                examples.append(followers)
                if leader["mandatory_without_value"]:
                    if self.comment_examples:
                        followers = CommentedMap()
                    else:
                        followers = {}
                    for follower in leadership.values():
                        if not follower["mandatory_without_value"]:
                            continue
                        if len(follower["names"]) == 1:
                            name = follower["names"][0]
                        else:
                            name = follower["names"][path_idx]
                        followers[name] = follower["gen_examples"][path_idx][leader_idx]
                        if self.comment_examples and "description" in follower:
                            description = follower["description"]
                            if description.endswith('.'):
                                description = description[:-1]
                            followers.yaml_add_eol_comment(description, name, column=self.comment_examples_column)
                    examples_mandatories.append(followers)
            break
        return examples, examples_mandatories
