"""
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 ruamel.yaml import YAML
from pathlib import Path
from itertools import chain

from rougail.error import ExtensionError
from tiramisu.error import ValueOptionError, PropertiesOptionError, LeadershipError
from rougail.utils import undefined
from tiramisu import MetaConfig

from .i18n import _
from .__version__ import __version__


class RougailUserDataYaml:
    has_several_layers = True

    def __init__(
        self,
        config,
        *,
        rougailconfig=None,
        **kwargs,
    ) -> None:
        if rougailconfig is None:
            from rougail import RougailConfig

            rougailconfig = RougailConfig
            user_data = rougailconfig["step.user_data"]
            if "yaml" not in user_data:
                user_data.append("yaml")
                rougailconfig["step.user_data"] = user_data
        user_data = rougailconfig["step.user_data"]
        if "yaml" not in user_data:
            raise ExtensionError(_("yaml is not set in step.user_data"))
        self.rougailconfig = rougailconfig
        self.filenames = []
        for filename in self.rougailconfig["yaml.filename"]:
            filename = Path(filename)
            if filename.is_file():
                self.filenames.append(filename)
            else:
                for name in sorted(
                    chain(filename.glob("*.yml"), filename.glob("*.yaml"))
                ):
                    self.filenames.append(name)

        self.file_with_secrets = self.rougailconfig["yaml.file_with_secrets"]
        self.errors = []
        self.warnings = []
        self.source = _('the YAML file "{0}"')

    def count_layers(self):
        return len(self.filenames)

    def run(
        self,
    ) -> None:
        self.yaml = YAML(typ="safe", pure=True)
        user_data = []
        if self.file_with_secrets == "last":
            last_filename_idx = len(self.filenames) - 1
        for idx, filename in enumerate(self.filenames):
            file_values = self.open(filename)
            if file_values is None:
                file_values = {}
            values = {}
            if not isinstance(file_values, dict):
                self.errors.append(
                    _(
                        'cannot load "{0}", the root value is not a dict but "{1}"'
                    ).format(filename, file_values)
                )
            else:
                self.parse(
                    values,
                    "",
                    file_values,
                    filename,
                )
            if self.file_with_secrets == "none":
                allow_secrets_variables = False
            elif self.file_with_secrets == "first":
                allow_secrets_variables = idx == 0
            elif self.file_with_secrets == "last":
                allow_secrets_variables = idx == last_filename_idx
            else:
                allow_secrets_variables = True
            user_data.append(
                {
                    "source": self.source.format(filename),
                    "errors": self.errors,
                    "warnings": self.warnings,
                    "values": values,
                    "options": {
                        "allow_secrets_variables": allow_secrets_variables,
                    },
                }
            )
        return user_data

    def open(self, filename: str) -> dict:
        with filename.open() as fh_config:
            return self.yaml.load(fh_config)

    def parse(
        self,
        values: dict,
        parent_path: str,
        file_values: dict,
        filename: str,
    ):
        for key, value in file_values.items():
            path = parent_path + key
            if isinstance(value, dict):
                self.parse(values, path + ".", value, filename)
            elif isinstance(value, list) and value and isinstance(value[0], dict):
                # it's a sequence
                keys = []
                for val in value:
                    if not isinstance(val, dict):
                        self.errors.append(
                            _('"{0}" in {1} has an unknown value').format(
                                path, filename
                            )
                        )
                        break
                    for v in val:
                        if v not in keys:
                            keys.append(v)
                else:
                    for val in value:
                        for key in keys:
                            values.setdefault(path + "." + key, []).append(
                                val.get(key, undefined)
                            )

            else:
                values[path] = value


RougailUserData = RougailUserDataYaml


__all__ = ("RougailUserDataYaml",)
