#!/usr/bin/env perl

use strict;
# use XXX;

sub main {
    my ($cmd) = @_;
    my $input = do { local $/; <> };
    my $input2 = do { local $/; <> };
    my ($options_spec) = $input2 =~ m/ ^ GETOPT_SPEC="\\ $ (.*?) ^ " $/xsm;
    $options_spec =~ s/.*Options:\n--//s;

    my @options;
    for my $line (split m/\n/, $options_spec) {
        next unless $line =~ m/\S/;
        my $arg = 0;
        my ($key, $desc) = split ' ', $line, 2;
        if ($key =~ s/=$//) {
            $arg = 1;
        }
        my @keys = split m/,/, $key;
        push @options, { keys => \@keys, arg => $arg, desc => $desc };
    }


    $input =~ s/.*?\n= Commands\n//s;
    $input =~ s/(.*?\n)==? .*/$1/s;
    my @list;
    my @subdir_cmds;
    while ($input =~ s/.*?^- (.*?\n)(?=- |== |\z)//ms) {
        my $text = $1;
        $text =~ /\A(.*)\n/
            or die "Bad text '$text'";
        my $usage = $1;
        $usage =~ s/\A`(.*)`\z/$1/
            or die "Bad usage: '$text'";
        my ($x1, $x2, $name) = split / +/, $usage;
        push @list, $name;
        if ($usage =~ m#\Q$name\E \[?<subdir>\]?# and $name ne "init") {
            push @subdir_cmds, $name;
        }
    }
    @subdir_cmds = sort @subdir_cmds;
    @list = sort @list;

    if ($cmd eq "bash") {
        generate_bash(\@list, \@subdir_cmds, \@options);
    }
    else {
        generate_zsh(\@list, \@subdir_cmds, \@options);
    }

}

sub generate_zsh {
    my ($list, $subdir_cmds, $options) = @_;
    my $options_string = '';
    for my $opt (@$options) {
        my $keys = $opt->{keys};
        my $desc = $opt->{desc};
        $desc =~ s/'/'"'"'/g;
        # examples:
        #'(-c --count)'{-c,--count}'[Number of list items to show]:count' \
        #'--remote[Remote name (like "origin")]:remote' \
        my $arg = '';
        if ($opt->{arg}) {
            $arg = ":$keys->[0]";
        }
        my @keystrings = map { (length $_ > 1 ? "--" : "-") . $_ } @$keys;
        if (@$keys == 1) {
            $options_string .= sprintf "        '%s[%s]%s' \\\n",
                $keystrings[0], $desc, $arg;
        }
        elsif (@$keys > 1) {
            $options_string .= sprintf "        '(%s)'{%s}'[%s]%s' \\\n",
                (join ' ', @keystrings), (join ',', @keystrings), $desc, $arg;
        }
    }
    print <<'...';
#compdef git-subrepo -P git\ ##subrepo
#description perform git-subrepo operations

# DO NOT EDIT. This file generated by pkg/bin/generate-completion.pl.

_git-subrepo() {
    typeset -A opt_args
    local curcontext="$curcontext" state line context

    _arguments -s \
        '1: :->subcmd' \
        '*: :->args' \
...
    print <<"...";
$options_string && ret=0

    case \$state in
    subcmd)
        compadd @$list
    ;;

    args)
        case \$line[1] in

        clone)
            _arguments -C \\
                '1: :->subcmd' \\
                '2: :->repo' \\
                '*: :->subdir' \\
                    && ret=0
                case \$state in
                subdir|repo)
                    _files
                ;;
                esac
        ;;

        @{[ join '|', @$subdir_cmds ]})
            _compadd_subdirs
        ;;

        init)
            _files
        ;;

        help)
            compadd @$list
        ;;
        esac
    ;;
    esac

\}

_compadd_subdirs() {
    local subrepos
    IFS=\$'\\n' set -A subrepos `git subrepo status -q`
    compadd -X "subrepos: " \$subrepos
}
...
}

sub generate_bash {

    my ($list, $subdir_cmds, $options, $complete_fetch_limit) = @_;
    my $options_string = '';
    for my $opt (@$options) {
        my $keys = $opt->{keys};
        my $arg = '';
        if ($opt->{arg}) {
            $arg = "=";
        }
        my @keystrings = map { (length $_ > 1 ? "--" : "-") . $_ } @$keys;
        for my $key (@keystrings) {
            $options_string .= " $key$arg";
        }
    }

    print <<"...";
# DO NOT EDIT. This file generated by pkg/bin/generate-completion.pl.

_git_subrepo() {
    local _opts="$options_string"
    local subcommands="@$list"
    local subdircommands="@$subdir_cmds"
    local subcommand="\$(__git_find_on_cmdline "\$subcommands")"

    if [ -z "\$subcommand" ]; then
        # no subcommand yet
        case "\$cur" in
        -*)
            __gitcomp "\$_opts"
        ;;
        *)
            __gitcomp "\$subcommands"
        esac

    else

        case "\$cur" in
        -*)
            __gitcomp "\$_opts"
            return
        ;;
        esac

        if [[ "\$subcommand" == "help" ]]; then
            __gitcomp "\$subcommands"
            return
        fi

        local subdircommand="\$(__git_find_on_cmdline "\$subdircommands")"
        if [ ! -z "\$subdircommand" ]; then
            local git_subrepos=`git subrepo status -q`
            __gitcomp "\$git_subrepos"
        fi

    fi
}
...

}

main(shift);
