#!/usr/bin/env python
import argparse
import json
import os
import sys

import awscli.clidriver
from awscli.help import PagingHelpRenderer

REF_PATH = 'reference'
TUT_PATH = 'tutorial'
TOPIC_PATH = 'topic'


class FileRenderer(PagingHelpRenderer):
    def __init__(self, file_path):
        self._file_path = file_path

    def render(self, contents):
        fp = open(self._file_path, 'wb')
        fp.write(contents)
        fp.close()


def do_operation(driver, service_path, operation_name, operation_command):
    file_path = os.path.join(service_path, operation_name + '.rst')
    help_command = operation_command.create_help_command()
    if help_command is None:
        # Do not document anything that does not have a help command.
        return
    help_command.doc.target = 'html'
    help_command.renderer = FileRenderer(file_path)
    help_command(None, None)


def do_service(
    driver, ref_path, service_name, service_command, is_top_level_service=True
):
    if is_top_level_service:
        print('...%s' % service_name)
    service_path = os.path.join(ref_path, service_name)
    if not os.path.isdir(service_path):
        os.mkdir(service_path)
    index_path = os.path.join(service_path, 'index.rst')
    help_command = service_command.create_help_command()
    if help_command is None:
        # Do not document anything that does not have a help command.
        return
    help_command.doc.target = 'html'
    help_command.renderer = FileRenderer(index_path)
    help_command(None, None)
    for operation_name in help_command.command_table:
        if operation_name == 'help':
            continue
        operation_command = help_command.command_table[operation_name]
        subcommand_table = getattr(operation_command, 'subcommand_table', {})
        # If the operation command has a subcommand table with commands
        # in it, treat it as a service command as opposed to an operation
        # command.
        if len(subcommand_table) > 0:
            do_service(
                driver, service_path, operation_name, operation_command, False
            )
        else:
            do_operation(
                driver, service_path, operation_name, operation_command
            )


def do_topic(driver, topic_path, topic_help_command):
    print('...%s' % topic_help_command.name)
    file_path = os.path.join(topic_path, topic_help_command.name + '.rst')
    topic_help_command.doc.target = 'html'
    topic_help_command.renderer = FileRenderer(file_path)
    topic_help_command(None, None)


def do_provider(driver):
    help_command = driver.create_help_command()
    help_command.doc.target = 'html'
    help_command.renderer = FileRenderer(os.path.join(REF_PATH, 'index.rst'))
    help_command(None, None)

    topic_help_command = help_command.subcommand_table['topics']
    topic_help_command.renderer = FileRenderer(
        os.path.join(TOPIC_PATH, 'index.rst')
    )
    topic_help_command.doc.target = 'html'
    help_command(['topics'], None)
    topics = help_command.subcommand_table
    print('Writing topics:')
    for topic in topics:
        if topic == 'topics':
            continue
        topic_help_command = help_command.subcommand_table[topic]
        do_topic(driver, TOPIC_PATH, topic_help_command)

    services = sorted(help_command.command_table)
    print('\nWriting service references')
    for service_name in services:
        if service_name == 'help':
            continue
        service_command = help_command.command_table[service_name]
        do_service(driver, REF_PATH, service_name, service_command)


def build_service_list(tut_path, ref_path, driver):
    file_path = os.path.join(tut_path, 'services.rst')
    fp = open(file_path, 'w')
    fp.write('\n')
    l = []
    help_command = driver.create_help_command()
    for service_name in help_command.command_table:
        if service_name == 'help':
            continue
        service_command = help_command.command_table[service_name]
        if not hasattr(service_command, '_service_object'):
            continue
        service = service_command._service_object
        l.append((service.service_full_name, service_name))
    l = sorted(l, key=lambda x: x[1])
    for full_name, service_name in l:
        service_ref_path = os.path.join(ref_path, service_name)
        service_ref_path = os.path.join(service_ref_path, 'index')
        fp.write(f'* :doc:`{full_name} <..{os.path.sep}{service_ref_path}>`\n')
    fp.write('\n')
    fp.close()


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        '-s', '--service', help='Name of service, or else all services'
    )
    parser.add_argument(
        '-o',
        '--operations',
        help='Name of operations, or else all operations',
        nargs='*',
    )
    args = parser.parse_args()
    driver = awscli.clidriver.create_clidriver()
    if not os.path.isdir(REF_PATH):
        os.mkdir(REF_PATH)
    if not os.path.isdir(TUT_PATH):
        os.mkdir(TUT_PATH)
    if not os.path.isdir(TOPIC_PATH):
        os.mkdir(TOPIC_PATH)
    print('Generating ReST documents for all services...')
    do_provider(driver)
    print('Generating service list ReST document...')
    build_service_list(TUT_PATH, REF_PATH, driver)
    print('Done!')
