#!/usr/bin/env python
"""Generate zsh completion script.

Usage
-----
.. code-block:: zsh
    devscripts/zsh-completion.py
    sudo mv youtube-dl.zsh /usr/share/zsh/site-functions/_youtube-dl
    rm -f ~/.zcompdump  # optional
    compinit  # regenerate ~/.zcompdump

Debug
-----
.. code-block:: zsh
    devscripts/zsh-completion.py MODULE_NAME -  # will output to stdout

Refer
-----
- https://github.com/ytdl-org/youtube-dl/blob/master/devscripts/zsh-completion.py
- https://github.com/zsh-users/zsh/blob/master/Etc/completion-style-guide

Examples
--------
.. code-block::
    '(- *)'{-h,--help}'[show this help message and exit]'
    |<-1->||<---2--->||<---------------3--------------->|

.. code-block:: console
    % foo --<TAB>
    option
    --help      show this help message and exit
    % foo --help <TAB>
    no more arguments

.. code-block::
    --color'[When to show color. Default: auto. Support: auto, always, never]:when:(auto always never)'
    |<-2->||<------------------------------3------------------------------->||<4>||<--------5-------->|

.. code-block:: console
    % foo --color <TAB>
    when
    always
    auto
    never

.. code-block::
    --color'[When to show color. Default: auto. Support: auto, always, never]:when:((auto\:"only when output is stdout" always\:always never\:never))'
    |<-2->||<------------------------------3------------------------------->||<4>||<--------------------------------5------------------------------->|

.. code-block:: console
    % foo --color <TAB>
    when
    always   always
    auto     only when output is stdout
    never    never

.. code-block::
    --config='[Config file. Default: ~/.config/foo/foo.toml]:config file:_files -g *.toml'
    |<--2-->||<---------------------3--------------------->||<---4---->||<------5------->|

.. code-block:: console
    % foo --config <TAB>
    config file
    a.toml  b/ ...
    ...

.. code-block::
    {1,2}'::_command_names -e'
    |<2->|4|<-------5------->|

.. code-block:: console
    % foo help<TAB>
    _command_names -e
    help2man  generate a simple manual page
    helpviewer
    ...
    % foo hello hello <TAB>
    no more arguments

.. code-block::
    '*: :_command_names -e'
    2|4||<-------5------->|

.. code-block:: console
    % foo help<TAB>
    external command
    help2man  generate a simple manual page
    helpviewer
    ...
    % foo hello hello help<TAB>
    external command
    help2man  generate a simple manual page
    helpviewer
    ...

+----+------------+----------+------+
| id | variable   | required | expr |
+====+============+==========+======+
| 1  | prefix     | F        | (.*) |
| 2  | optionstr  | T        | .*   |
| 3  | helpstr    | F        | [.*] |
| 4  | metavar    | F        | :.*  |
| 5  | completion | F        | :.*  |
+----+------------+----------+------+
"""
from __future__ import unicode_literals
from optparse import SUPPRESS_HELP
import os
from os.path import dirname as dirn
import sys
from typing import Final

from setuptools import find_packages

rootpath = dirn(dirn(os.path.abspath(__file__)))
path = os.path.join(rootpath, "src")
packages = find_packages(path)
if packages == []:
    path = rootpath
sys.path.insert(0, path)
PACKAGE: Final = "youtube_dl" if sys.argv[1:2] == [] else sys.argv[1]
parser = __import__(PACKAGE).parseOpts()[0]
BINNAME: Final = PACKAGE.replace("_", "-")
BINNAMES: Final = [BINNAME]
ZSH_COMPLETION_FILE: Final = (
    "youtube-dl.zsh" if sys.argv[2:3] == [] else sys.argv[2]
)
ZSH_COMPLETION_TEMPLATE = "devscripts/zsh-completion.in"

opts = parser._get_all_options()

flags = []
for opt in opts:
    optionstrs = opt._long_opts + opt._short_opts
    if len(optionstrs) == 1:
        optionstr = optionstrs[0]
    else:
        optionstr = "'{" + ",".join(optionstrs) + "}'"

    if opt.action in ["help", "version"]:
        prefix = "- *"
    else:
        prefix = " ".join(optionstrs)
    prefix = "'(" + prefix + ")"

    if opt.help == SUPPRESS_HELP:
        helpstr = ""
    else:
        helpstr = opt.help.replace("'", "'\\''").replace("]", "\\]")
        helpstr = "[" + helpstr + "]"

    if isinstance(opt.metavar, str):
        metavar = opt.metavar
    elif optionstr == "--external-downloader-args":
        metavar = " "  # use default
    else:  # opt.metavar is None
        metavar = ""
    if metavar != "":
        # use lowcase conventionally
        metavar = metavar.lower().replace(":", "\\:")

    if opt.choices:
        completion = "(" + " ".join(opt.choices) + ")"
    elif optionstr == "--external-downloader-args":
        completion = "->external-downloader-args"
    elif metavar == "file":
        completion = "_files"
        metavar = " "
    elif metavar == "dir":
        completion = "_dirs"
        metavar = " "
    elif metavar == "url":
        completion = "_urls"
        metavar = " "
    elif metavar == "command":
        completion = "_command_names -e"
        metavar = " "
    else:
        completion = ""

    if metavar != "":
        metavar = ":" + metavar
    if completion != "":
        completion = ":" + completion

    flag = "{0}{1}{2}{3}{4}'".format(
        prefix, optionstr, helpstr, metavar, completion
    )

    flags += [flag]

with open(ZSH_COMPLETION_TEMPLATE) as f:
    template = f.read()

template = template.replace("{{programs}}", " ".join(BINNAMES))
template = template.replace("{{flags}}", " \\\n  ".join(flags))

with (
    open(ZSH_COMPLETION_FILE, "w")
    if ZSH_COMPLETION_FILE != "-"
    else sys.stdout
) as f:
    f.write(template)