"""
Generates a list of task-related modules and classes to be used by sphinx.

"""
import os
import argparse
import sys
import time
import stevedore
from luigi.task_register import Register


SPHINX_DIR = os.path.dirname(__file__)


def gen_sphinx_tasks(entry_point, labels, *_args, **kwargs):
    """
    Writes a file per label, suitable for use by sphinx.ext.autodoc,
    using the classes found from entry_point.

    Also generates toctree.inc, which can be included from the index
    page to provide links to each generated file.

    """
    # Declare file header strings
    warning = '''..  WARNING: DO NOT EDIT THIS FILE DIRECTLY
    Generated by sphinx_source/gen_tasks.py on {now}

    '''.format(now=time.strftime('%c'))

    toctree_header = '''{warning}
.. toctree::
   :maxdepth: 1
'''
    incfile_header = '''{warning}
..  _{category_slug}:

Back to :doc:`index`

{label_heading}
'''

    # Load modules into memory
    stevedore.ExtensionManager(entry_point)

    # Used to filter the classes under entry_point
    entry_point_dot = '{entry_point}.'.format(entry_point=entry_point)

    # Generate a list of output file arguments from the given labels and categories
    output = []
    categories = kwargs.get('categories', [])
    for idx, label in enumerate(labels):
        try:
            category = ''
            if idx < len(categories):
                category = categories[idx]

            # Create a category slug for sphinx, and name the file with it
            category_slug = category.replace(' ', '_') or 'all'
            file_name = '{slug}.rst'.format(slug=category_slug)
            file_path = os.path.join(SPHINX_DIR, file_name)
            file_pointer = open(file_path, "w")
            output.append({
                'fp': file_pointer,
                'file_name': file_name,
                'category': category,
                'category_slug': category_slug,
                'label': label,
                'label_heading': "{label}\n{_}".format(label=label, _='=' * len(label)),
                'modules': {},
            })
        except IOError:
            sys.exit('Unable to write to {file_path}'.format(file_path=file_path))

    # Write the header to the table of contents file
    tocfile_name = os.path.join(SPHINX_DIR, 'toctree.rst')
    try:
        tocfile = open(tocfile_name, "w")
        tocfile.write(toctree_header.format(warning=warning))
    except IOError:
        sys.exit('Unable to write to {file_name}'.format(file_name=tocfile_name))

    # For each Task, sorted by class name
    tasks = Register._get_reg()
    for name in sorted(tasks):
        cls = tasks[name]
        module = cls.__module__
        # Show only tasks under entry_point
        if module.startswith(entry_point_dot):
            for out in output:
                # Show only tasks in the output category
                if getattr(cls, 'task_category', '') == out['category']:
                    if module not in out['modules']:
                        out['modules'][module] = {}
                    out['modules'][module][name] = cls

    for out in output:
        modules = sorted(out['modules'].keys())
        if modules:
            tocfile.write("\n   {incfile}".format(incfile=out['file_name']))
            out['fp'].write(incfile_header.format(warning=warning, **out))

        for module in modules:
            # Strip off entry_point to avoid redundancy in documentation
            module_heading = '{module}'.format(module=module.replace(entry_point_dot, ''))
            out['fp'].write("\n\n{module_heading}\n{_}".format(
                module_heading=module_heading, _='-' * len(module_heading)))
            out['fp'].write("\n\n.. automodule:: {module}".format(module=module))

            names = out['modules'][module]
            for name in sorted(names):
                out['fp'].write("\n\n.. autoclass:: {name}".format(name=name))

        out['fp'].close()

    tocfile.close()


def main():
    """
    Parse the command line arguments, and call gen_sphinx_task

    """
    parser = argparse.ArgumentParser(description='Generate Sphinx RST files for each category of tasks.')
    parser.add_argument('--entry-point', type=str, required=True,
                        metavar='edx.analytics.tasks',
                        help='Name of the entry point to start searching from')
    parser.add_argument('--labels', type=str, nargs='+', required=True,
                        metavar='Category Label',
                        help='Category label(s) to use when generating task include file(s)')
    parser.add_argument('--categories', type=str, nargs='*',
                        metavar='workflow_entry_point',
                        help='Provide one per --label to filter the tasks marked with the given category.'
                        ' An empty string means "all tasks".')

    args = vars(parser.parse_args())

    gen_sphinx_tasks(**args)

if __name__ == "__main__":
    main()
