"""
Silique (https://www.silique.fr)
Copyright (C) 2024-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 rougail.utils import load_modules
from .i18n import _


ROUGAIL_VARIABLE_TYPE = (
    "https://rougail.readthedocs.io/en/latest/variable.html#variables-types"
)


OUTPUTS = None
TABLES = None


def get_outputs_or_tables(type_) -> None:
    """Load all outputs or tables"""
    module_name = f"rougail.output_doc.{type_}"
    outputs = {}
    names = []
    for path in (Path(__file__).parent / type_).iterdir():
        name = path.name
        if not name.endswith(".py") or name.endswith("__.py"):
            continue
        module = load_modules(module_name + "." + name[:-3], str(path))
        if type_ == "output":
            if "Formatter" not in dir(module):
                continue
            obj_class = module.Formatter
        elif type_ == "table":
            if "Table" not in dir(module):
                continue
            obj_class = module.Table
        level = obj_class.level
        if level in outputs:
            raise ImportError(
                _('duplicated level rougail-output-doc for {0} "{1}": {2} and {3}').format(
                    type_, level, obj_class.name, outputs[level].name
                )
            )
        if obj_class.name in names:
            raise ImportError(
                _('duplicated name "{0}" in rougail-output-doc').format(
                    obj_class.name
                )
            )
        names.append(obj_class.name)
        outputs[level] = obj_class
    return {outputs[level].name: outputs[level] for level in sorted(outputs)}


class OutPuts:  # pylint: disable=R0903
    """Transformations applied on a object instance"""

    def __init__(
        self,
    ) -> None:
        global OUTPUTS
        if OUTPUTS is None:
            OUTPUTS = get_outputs_or_tables("output")

    def get(self) -> dict:
        """Get all outputs"""
        return OUTPUTS


class Tables:  # pylint: disable=R0903
    """Transformations applied on a object instance"""

    def __init__(
        self,
    ) -> None:
        global TABLES
        if TABLES is None:
            TABLES = get_outputs_or_tables("table")

    def get(self) -> dict:
        """Get all tables"""
        return TABLES


def get_rougail_config(
    *,
    backward_compatibility=True,  # pylint: disable=unused-argument
) -> dict:
    """Get documentation for output_doc modules"""
    outputs = list(OutPuts().get())
    output_format_default = outputs[0]
    tables = list(Tables().get())
    table_default = tables[0]
    rougail_options = f"""
doc:
  description: {_('Generate documentation')}
  disabled:
    jinja: |
      {{% if step.output is propertyerror or step.output != 'doc' %}}
      disabled
      {{% endif %}}
    description: {_('when "doc" is not set in "step.output"')}

  title_level:
    description: {_('Starting title level')}
    alternative_name: dt
    default: 1

  contents:
    description: {_('Generated content')}
    alternative_name: dc
    choices:
      - variables
      - example
      - changelog
    default:
      - variables

  previous_json_file:
    description: {_('Previous description file in JSON format')}
    alternative_name: dp
    disabled:
      jinja: |-
        {{{{ "changelog" not in _.contents }}}}
      return_type: boolean
      description: {_('changelog is not selected in "_.contents"')}

  without_family: 
    description: {_('Do not add families in documentation')}
    default: false
    alternative_name: df
    disabled:
      jinja: |-
        {{{{ _.output_format == "json" or ("variables" not in _.contents and "changelog" not in _.contents) }}}}
      return_type: boolean
      description: {_('if "_.output_format" is json or "_.contents" hasn\'t variable or changelog')}

  root:
    description: {_('Document the variables from this family')}
    alternative_name: dr
    mandatory: false

  with_commandline:
    description: {_('Add command line informations in documentation')}
    alternative_name: dw
    default: false
    disabled:
      jinja: |-
        {{{{ _.output_format == "json" or ("variables" not in _.contents and "changelog" not in _.contents) }}}}
      return_type: boolean
      description: {_('if "_.output_format" is json or "_.contents" hasn\'t variable or changelog')}

  with_environment:
    description: {_('Add environment variable informations in documentation')}
    alternative_name: de
    default: false
    disabled:
      jinja: |-
        {{{{ _.output_format == "json" or ("variables" not in _.contents and "changelog" not in _.contents) }}}}
      return_type: boolean
      description: {_('if "_.output_format" is json or "_.contents" hasn\'t variable or changelog')}

  environment_default_environment_name:
    description: {_("Name of the default environment prefix")}
    alternative_name: dd
    default: ROUGAIL
    validators:
      - jinja: |-
          {{{{ (_.environment_default_environment_name | upper) != _.environment_default_environment_name }}}}
        return_type: boolean
        description: {_("should only user uppercase characters")}
    disabled:
      jinja: |-
        {{{{ __.main_namespace == none or _.with_environment is false }}}}
      return_type: boolean
      description: {_('when "__.main_namespace" is not set or "_.with_environment" is false')}

  other_root_filenames:
    description: {_("Families or variables for this family are in an other file name")}
    type: leadership
    disabled:
      jinja: |-
        {{% if not _.root %}}
          Documents are not splitted
        {{% endif %}}
      description: {_('documentation must be splitted')}

    root_path:
      description: {_("Root family name")}
      mandatory: false

    filename:
      description: {_("Name of the file")}
      type: unix_filename
      params:
        allow_relative: true

  disabled_modes:
    description: {_('Disable documentation for variables with those modes')}
    multi: true
    mandatory: false
    disabled:
      jinja: |
        {{% if not modes_level %}}
        there is no mode
        {{% endif %}}
      description: {_('disabled when there is no mode available')}
    validators:
      - jinja: |
          {{% if _.disabled_modes not in modes_level %}}
          this mode is not available
          {{% endif %}}
        description: {_('verify if disable modes already exists')}

  change_default_value: true  # {_('Modify values to document leaderships and dynamics families')}

  comment_examples:
    description: {_('Add description of variables and families when generate examples')}
    alternative_name: dx
    default: false
    disabled:
      jinja: |-
        {{{{ "example" not in _.contents }}}}
      return_type: boolean
      description: {_('disabled when example in not in contents')}

  comment_examples_column:
    description: {_('Comment in examples starts at column')}
    default: 30
    disabled:
      variable: _.comment_examples
      propertyerror: false
      when: false

  output_format:
    description: {_('Generate document in format')}
    alternative_name: do
    default: { output_format_default }
    validators:
      - jinja: |-
          {{% if _.output_format == 'json' %}}
            {{% if "changelog" in _.contents or "example" in _.contents %}}
              cannot add to contents "{{{{ _.contents }}}}" with output_format "json"
            {{% endif %}}
          {{% endif %}}
        description: {_('json output_format is not compatible with "changelog" and "example" contents')}
    choices:
"""
    for output in outputs:
        rougail_options += f"      - {output}\n"
    rougail_options += f"""
  table_model:
    description: {_('Generate document inside table model')}
    alternative_name: dm
    default: { table_default }
    validators:
      - jinja: |-
          {{% if _.output_format == 'json' %}}
            {{% if "changelog" in _.contents or "example" in _.contents %}}
              cannot add to contents "{{{{ _.contents }}}}" with output_format "json"
            {{% endif %}}
          {{% endif %}}
        description: {_('json output_format is not compatible with "changelog" and "example" contents')}
    choices:
"""
    for table in tables:
        rougail_options += f"      - {table}\n"
    rougail_options += f"""
  force_true_color_terminal:
      description: {_('Force true color terminal')}
      default: false
"""
    return {
        "name": "doc",
        "process": "output",
        "options": rougail_options,
        "allow_user_data": False,
        "level": 50,
    }


__all__ = ("OutPuts", "get_rougail_config")
