#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Oasis LMF documentation build configuration file, created by
# sphinx-quickstart on Thu Feb  1 12:22:30 2018.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))


# -- General configuration ------------------------------------------------

# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'

import datetime
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
import os
import subprocess
import sys

from sphinx.ext import autodoc

ROOT_PATH = os.path.join(os.path.dirname(__file__), os.path.pardir, os.path.pardir)

sys.path.append(ROOT_PATH)
from oasislmf import __version__  # noqa
from oasislmf.cli.model import RunCmd
from oasislmf.computation.run.model import RunModel
from oasislmf.computation.run.exposure import RunExposure
from oasislmf.computation.run.platform import PlatformBase, PlatformRun

extensions = [
    'sphinx.ext.autodoc',
    'sphinx.ext.autosummary',
    'sphinx.ext.intersphinx',
    'sphinx.ext.coverage',
    'sphinx.ext.viewcode',
    'sphinx.ext.githubpages',
    'autoapi.extension',
]


# API Generation
autoapi_dirs = ['../../oasislmf']
autoapi_options = [
    "members",
    # "inherited-members",  # errors
    "undoc-members",
    "show-inheritance",
    "show-module-summary",
]
autoapi_keep_files = False

# Add any paths that contain templates here, relative to this directory.
# templates_path = ['_templates']

# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'

# The master toctree document.
master_doc = 'index'

# General information about the project.
project = u'Oasis LMF'
author = u'Oasis LMF'
year_now = datetime.date.today().year
copyright = str(year_now) + ' Oasis LMF'

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = __version__
# The full version, including alpha/beta/rc tags.
release = __version__

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = 'en'

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = []

# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'friendly'

# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True


# -- Options for HTML output ----------------------------------------------

# The theme to use for HTML and HTML Help pages.  See the documentation for
# a list of builtin themes.
#
html_theme = 'furo'
html_title = "Oasis LMF Documentation"

html_css_files = [
    'https://fonts.googleapis.com/css?family=Raleway',
]
# Theme options are theme-specific and customize the look and feel of a theme
# further.  For a list of options available for each theme, see the
# documentation.
#
html_theme_options = {
    "footer_icons": [
        {
            "name": "GitHub",
            "url": "https://github.com/OasisLMF",
            "html": """
                <svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 16 16">
                    <path fill-rule="evenodd" d="M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z"></path>
                </svg>
            """,
            "class": "",
        },
    ],

    "light_css_variables": {
        "color-brand-primary": " #862633",
        "color-brand-content": "#d22630",
        "font-stack": "Raleway, sans-serif",
        "font-stack--monospace": "Courier, monospace",
    }
}

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
# html_static_path = ['_static']

# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# This is required for the alabaster theme
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
# html_sidebars = {
#     '**': [
#         'about.html',
#         'navigation.html',
#         'relations.html',  # needs 'show_related': True theme option to display
#         'searchbox.html',
#         'donate.html',
#         'versioning.html'
#     ]
# }


# -- Options for HTMLHelp output ------------------------------------------

# Output file base name for HTML help builder.
htmlhelp_basename = 'OasisLMFdoc'


# -- Options for LaTeX output ---------------------------------------------

latex_elements = {
    # The paper size ('letterpaper' or 'a4paper').
    #
    # 'papersize': 'letterpaper',

    # The font size ('10pt', '11pt' or '12pt').
    #
    # 'pointsize': '10pt',

    # Additional stuff for the LaTeX preamble.
    #
    # 'preamble': '',

    # Latex figure (float) alignment
    #
    # 'figure_align': 'htbp',
}

# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
#  author, documentclass [howto, manual, or own class]).
latex_documents = [
    (master_doc, 'OasisLMF.tex', 'Oasis LMF Documentation',
     'Oasis Loss Modelling Framework', 'manual'),
]


# -- Options for manual page output ---------------------------------------

# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
    (master_doc, 'oasislmf', 'Oasis LMF Documentation',
     [author], 1)
]


# -- Options for Texinfo output -------------------------------------------

# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
#  dir menu entry, description, category)
texinfo_documents = [
    (master_doc, 'OasisLMF', 'Oasis LMF Documentation',
     author, 'OasisLMF', 'One line description of project.',
     'Miscellaneous'),
]


# -- Options for Epub output ----------------------------------------------

# Bibliographic Dublin Core info.
epub_title = project
epub_author = author
epub_publisher = author
epub_copyright = copyright

# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#
# epub_identifier = ''

# A unique identification for the text.
#
# epub_uid = ''

# A list of files that should not be packed into the epub file.
epub_exclude_files = ['search.html']


# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'python': ('https://docs.python.org/', None)}


def list_options():
    # Get params from RunCmd
    cmd_opts = RunCmd().arg_parser._actions
    cmd_opts.pop(0)

    # Retrieve params from all other relevant subcommands
    runmodel_info = RunModel.get_params()
    runexposure_info = RunExposure.get_params()
    platformbase_info = PlatformBase.get_params()
    platformrun_info = PlatformRun.get_params()

    # Populate a dictionary with all the params from subcommands
    all_params = {param['name']: param for param in runmodel_info}
    all_params.update({param['name']: param for param in runexposure_info})
    all_params.update({param['name']: param for param in platformbase_info})
    all_params.update({param['name']: param for param in platformrun_info})

    rst_output = []

    # Create a dictionary from cmd_opts
    cmd_opts_dict = {}
    for opt in cmd_opts:
        param_name = opt.dest
        expected_type = opt.type if opt.type else 'string'
        cmd_opts_dict[param_name] = {
            'help': opt.help,
            'default': opt.default,
            'expected_type': expected_type,
            'option_strings': opt.option_strings
        }

    # Update cmd_opts with details from subcommand params
    for param_name, param_entry in all_params.items():
        if param_name in cmd_opts_dict:
            cmd_opt = cmd_opts_dict[param_name]
            if cmd_opt['default'] is None and 'default' in param_entry:
                cmd_opt['default'] = param_entry['default']
            if 'type' in param_entry:
                cmd_opt['expected_type'] = param_entry['type']
            if param_entry.get('is_path', False):
                cmd_opt['expected_type'] = "path"
        else:
            cmd_opts_dict[param_name] = {
                'help': param_entry.get('help', ''),
                'default': param_entry.get('default', None),
                'expected_type': param_entry.get('type', 'string'),
                'option_strings': []
            }
            if param_entry.get('is_path', False):
                cmd_opts_dict[param_name]['expected_type'] = "path"

    # Remove options that are exclusively passed as data during execution
    cmd_opts_dict = {k: v for k, v in cmd_opts_dict.items() if k not in ['profile_loc', 'profile_acc', 'profile_fm_agg']}

    # Reformat expected_type
    for cmd_opt in cmd_opts_dict.values():
        expected_type_str = str(cmd_opt['expected_type'])
        if "<function str2bool at" in expected_type_str:
            cmd_opt['expected_type'] = "boolean (yes/no, true/false t/f, y/n, or 1/0)"
        elif "<oasislmf.utils.path.PathCleaner" in expected_type_str:
            cmd_opt['expected_type'] = "path"
        elif "<class 'int'>" in expected_type_str:
            cmd_opt['expected_type'] = "integer"

    # Generate RST output
    rst_output = []
    for param_name, cmd_opt in cmd_opts_dict.items():
        rst_output.extend([
            f'{param_name}',
            '=' * len(param_name),
            '',
            f'Description: {cmd_opt["help"]}',
            '',
            f'Expected type: {cmd_opt["expected_type"]}',
            '',
            f'Default value: ``{cmd_opt["default"]}``',
            '',
        ])

    with open('./source/generated_options.rst', 'w') as f:
        f.write('\n'.join(rst_output))


class CliDocumenter(autodoc.ClassDocumenter):
    objtype = "cli"

    # do not indent the content
    content_indent = ""

    # do not add a header to the docstring
    def add_directive_header(self, sig):
        pass


def setup(app):
    app.add_autodocumenter(CliDocumenter)
    list_options()
