#!/usr/bin/env python3

"""
Auto-generates documentation from command defs in console.py.
"""

import click
import html
import os
import re
import shutil
import textwrap

from click import Command

from twitchdl.cli import cli


START_MARKER = "<!-- ------------------- generated docs start ------------------- -->"
END_MARKER = "<!-- ------------------- generated docs end ------------------- -->"


def main():
    update_changelog()

    parent_ctx = click.Context(cli, info_name="twitch-dl")
    for name, command in cli.commands.items():
        ctx = click.Context(cli, info_name=name, parent=parent_ctx)
        update_docs(command, ctx)


def update_changelog():
    print("Updating: docs/changelog.md")
    root = os.path.realpath(os.path.dirname(os.path.dirname(__file__)))
    source = os.path.join(root, "CHANGELOG.md")
    target = os.path.join(root, "docs/changelog.md")
    shutil.copy(source, target)


def update_docs(command: Command, ctx: click.Context):
    path = os.path.join("docs", "commands", f"{command.name}.md")
    content = render_command(command, ctx)

    if not os.path.exists(path):
        print(f"Creating: {path}")
        write(path, content)
    else:
        print(f"Updating: {path}")
        [_, handwritten] = read(path).split(END_MARKER)
        content = f"{content.strip()}\n\n{END_MARKER}\n\n{handwritten.strip()}"
        write(path, content)


def render_command(command: Command, ctx: click.Context):
    content = START_MARKER
    content += f"\n# twitch-dl {command.name}\n\n"

    if command.help:
        content += textwrap.dedent(command.help).strip() + "\n\n"

    content += render_usage(ctx, command)
    content += render_options(ctx, command)
    return content


def render_usage(ctx: click.Context, command: Command):
    content = "### USAGE\n\n"
    content += "```\n"
    content += command.get_usage(ctx).replace("Usage: ", "")

    content += "\n```\n\n"
    return content


def render_options(ctx, command: Command):
    options = list(get_options(command))

    if not options:
        return ""

    content = "### OPTIONS\n\n"

    content += "<table>\n"
    content += "<tbody>"
    for opts, help in options:
        content += textwrap.dedent(f"""
        <tr>
            <td class="code">{escape(opts)}</td>
            <td>{escape(help)}</td>
        </tr>
        """)
    content += "</tbody>\n"
    content += "</table>\n\n"

    return content


def get_options(command: Command):
    for option in command.params:
        if isinstance(option, click.Option):
            opts = ", ".join(option.opts)
            opts += option_type(option)

            help = option.help or ""
            help = re.sub(r"\s+", " ", help)
            help += choices(option)
            if option.default:
                help += f" [default: `{option.default}`]"

            yield opts, help


def option_type(option: click.Option):
    match option.type:
        case click.types.StringParamType():
            return " TEXT"
        case click.types.Choice():
            return " TEXT"
        case click.types.IntParamType():
            return " INTEGER"
        case _:
            return ""

def choices(option: click.Option):
    if isinstance(option.type, click.Choice):
        choices = ", ".join(f"`{c}`" for c in option.type.choices)
        return f" Possible values: {choices}."
    return ""


def read(path):
    with open(path, "r") as f:
        return f.read()


def write(path, content):
    with open(path, "w") as f:
        return f.write(content)


def escape(text: str):
    text = html.escape(text)
    text = re.sub(r"`([\S]+)`", "<code>\\1</code>", text)
    return text


if __name__ == "__main__":
    main()
