# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from __future__ import absolute_import

import importlib
import os
import sys

from sphinx.util.compat import Directive
from sphinx.util.docstrings import prepare_docstring


def function_reference(f, attr, args, doc):
    lines = []

    lines.extend([
        f,
        '-' * len(f),
        '',
    ])

    docstring = prepare_docstring(doc)

    lines.extend([
        docstring[0],
        '',
    ])

    arg_types = []

    for t in args:
        if isinstance(t, list):
            inner_types = [t2.__name__ for t2 in t]
            arg_types.append(' | ' .join(inner_types))
            continue

        arg_types.append(t.__name__)

    arg_s = '(%s)' % ', '.join(arg_types)

    lines.extend([
        ':Arguments: %s' % arg_s,
        '',
    ])

    lines.extend(docstring[1:])
    lines.append('')

    return lines


def variable_reference(v, st_type, in_type, doc, tier):
    lines = [
        v,
        '-' * len(v),
        '',
    ]

    docstring = prepare_docstring(doc)

    lines.extend([
        docstring[0],
        '',
    ])

    lines.extend([
        ':Storage Type: ``%s``' % st_type.__name__,
        ':Input Type: ``%s``' % in_type.__name__,
        '',
    ])

    lines.extend(docstring[1:])
    lines.append('')

    return lines


def special_reference(v, func, typ, doc):
    lines = [
        v,
        '-' * len(v),
        '',
    ]

    docstring = prepare_docstring(doc)

    lines.extend([
        docstring[0],
        '',
        ':Type: ``%s``' % typ.__name__,
        '',
    ])

    lines.extend(docstring[1:])
    lines.append('')

    return lines


def format_module(m):
    lines = []

    for subcontext, cls in sorted(m.SUBCONTEXTS.items()):
        lines.extend([
            '.. _mozbuild_subcontext_%s:' % subcontext,
            '',
            'Sub-Context: %s' % subcontext,
            '=============' + '=' * len(subcontext),
            '',
        ])
        lines.extend(prepare_docstring(cls.__doc__))
        if lines[-1]:
            lines.append('')

        for k, v in sorted(cls.VARIABLES.items()):
            lines.extend(variable_reference(k, *v))

    lines.extend([
        'Variables',
        '=========',
        '',
    ])

    for v in sorted(m.VARIABLES):
        lines.extend(variable_reference(v, *m.VARIABLES[v]))

    lines.extend([
        'Functions',
        '=========',
        '',
    ])

    for func in sorted(m.FUNCTIONS):
        lines.extend(function_reference(func, *m.FUNCTIONS[func]))

    lines.extend([
        'Special Variables',
        '=================',
        '',
    ])

    for v in sorted(m.SPECIAL_VARIABLES):
        lines.extend(special_reference(v, *m.SPECIAL_VARIABLES[v]))

    return lines


class MozbuildSymbols(Directive):
    """Directive to insert mozbuild sandbox symbol information."""

    required_arguments = 1

    def run(self):
        module = importlib.import_module(self.arguments[0])
        fname = module.__file__
        if fname.endswith('.pyc'):
            fname = fname[0:-1]

        self.state.document.settings.record_dependencies.add(fname)

        # We simply format out the documentation as rst then feed it back
        # into the parser for conversion. We don't even emit ourselves, so
        # there's no record of us.
        self.state_machine.insert_input(format_module(module), fname)

        return []


def setup(app):
    app.add_directive('mozbuildsymbols', MozbuildSymbols)

    # Unlike typical Sphinx installs, our documentation is assembled from
    # many sources and staged in a common location. This arguably isn't a best
    # practice, but it was the easiest to implement at the time.
    #
    # Here, we invoke our custom code for staging/generating all our
    # documentation.
    from moztreedocs import SphinxManager

    topsrcdir = app.config._raw_config['topsrcdir']
    manager = SphinxManager(topsrcdir,
        os.path.join(topsrcdir, 'tools', 'docs'),
        app.outdir)
    manager.generate_docs(app)

    app.srcdir = os.path.join(app.outdir, '_staging')

    # We need to adjust sys.path in order for Python API docs to get generated
    # properly. We leverage the in-tree virtualenv for this.
    from mozbuild.virtualenv import VirtualenvManager

    ve = VirtualenvManager(topsrcdir,
        os.path.join(topsrcdir, 'dummy-objdir'),
        os.path.join(app.outdir, '_venv'),
        sys.stderr,
        os.path.join(topsrcdir, 'build', 'virtualenv_packages.txt'))
    ve.ensure()
    ve.activate()
