#!/usr/bin/env python3


# Copyright 2018 The Meson development team

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#     http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

'''
Regenerate markdown docs by using `meson.py` from the root dir
'''

import argparse
import os
import re
import subprocess
import sys
import textwrap
import json
import typing as T
from pathlib import Path
from urllib.request import urlopen

PathLike = T.Union[Path,str]

def _get_meson_output(root_dir: Path, args: T.List) -> str:
    env = os.environ.copy()
    env['COLUMNS'] = '80'
    return subprocess.run([str(sys.executable), str(root_dir/'meson.py')] + args, check=True, capture_output=True, text=True, env=env).stdout.strip()

def get_commands_data(root_dir: Path) -> T.Dict[str, T.Any]:
    usage_start_pattern = re.compile(r'^usage: ', re.MULTILINE)
    positional_start_pattern = re.compile(r'^positional arguments:[\t ]*[\r\n]+', re.MULTILINE)
    options_start_pattern = re.compile(r'^optional arguments:[\t ]*[\r\n]+', re.MULTILINE)
    commands_start_pattern = re.compile(r'^[A-Za-z ]*[Cc]ommands:[\t ]*[\r\n]+', re.MULTILINE)

    def get_next_start(iterators: T.Sequence[T.Any], end: T.Optional[int]) -> int:
        return next((i.start() for i in iterators if i), end)

    def normalize_text(text: str) -> str:
        # clean up formatting
        out = text
        out = re.sub(r'\r\n', r'\r', out, flags=re.MULTILINE) # replace newlines with a linux EOL
        out = re.sub(r'^ +$', '', out, flags=re.MULTILINE) # remove trailing whitespace
        out = re.sub(r'(?:^\n+|\n+$)', '', out) # remove trailing empty lines
        return out

    def parse_cmd(cmd: str) -> T.Dict[str, str]:
        cmd_len = len(cmd)
        usage = usage_start_pattern.search(cmd)
        positionals = positional_start_pattern.search(cmd)
        options = options_start_pattern.search(cmd)
        commands = commands_start_pattern.search(cmd)

        arguments_start = get_next_start([positionals, options, commands], None)
        assert arguments_start

        # replace `usage:` with `$` and dedent
        dedent_size = (usage.end() - usage.start()) - len('$ ')
        usage_text = textwrap.dedent(f'{dedent_size * " "}$ {normalize_text(cmd[usage.end():arguments_start])}')

        return {
            'usage': usage_text,
            'arguments': normalize_text(cmd[arguments_start:cmd_len]),
        }

    def clean_dir_arguments(text: str) -> str:
        # Remove platform specific defaults
        args = [
            'prefix',
            'bindir',
            'datadir',
            'includedir',
            'infodir',
            'libdir',
            'libexecdir',
            'localedir',
            'localstatedir',
            'mandir',
            'sbindir',
            'sharedstatedir',
            'sysconfdir'
        ]
        out = text
        for a in args:
            out = re.sub(r'(--' + a + r' .+?)\s+\(default:.+?\)(\.)?', r'\1\2', out, flags=re.MULTILINE|re.DOTALL)
        return out

    output = _get_meson_output(root_dir, ['--help'])
    commands = {c.strip() for c in re.findall(r'usage:(?:.+)?{((?:[a-z]+,*)+?)}', output, re.MULTILINE|re.DOTALL)[0].split(',')}
    commands.remove('help')

    cmd_data = dict()

    for cmd in commands:
        cmd_output = _get_meson_output(root_dir, [cmd, '--help'])
        cmd_data[cmd] = parse_cmd(cmd_output)
        if cmd in ['setup', 'configure']:
            cmd_data[cmd]['arguments'] = clean_dir_arguments(cmd_data[cmd]['arguments'])

    return cmd_data

def generate_hotdoc_includes(root_dir: Path, output_dir: Path) -> None:
    cmd_data = get_commands_data(root_dir)

    for cmd, parsed in cmd_data.items():
        for typ in parsed.keys():
            with open(output_dir / (cmd+'_'+typ+'.inc'), 'w', encoding='utf-8') as f:
                f.write(parsed[typ])

def generate_wrapdb_table(output_dir: Path) -> None:
    url = urlopen('https://wrapdb.mesonbuild.com/v2/releases.json')
    releases = json.loads(url.read().decode())
    with open(output_dir / 'wrapdb-table.md', 'w', encoding='utf-8') as f:
        f.write('| Project | Versions | Provided dependencies | Provided programs |\n')
        f.write('| ------- | -------- | --------------------- | ----------------- |\n')
        for name, info in releases.items():
            versions = [f'[{v}](https://wrapdb.mesonbuild.com/v2/{name}_{v}/{name}.wrap)' for v in info['versions']]
            # Highlight latest version.
            versions_str = f'<big>**{versions[0]}**</big><br/>' + ', '.join(versions[1:])
            dependency_names = info.get('dependency_names', [])
            dependency_names_str = ', '.join(dependency_names)
            program_names = info.get('program_names', [])
            program_names_str = ', '.join(program_names)
            f.write(f'| {name} | {versions_str} | {dependency_names_str} | {program_names_str} |\n')

def regenerate_docs(output_dir: PathLike,
                    dummy_output_file: T.Optional[PathLike]) -> None:
    if not output_dir:
        raise ValueError(f'Output directory value is not set')

    output_dir = Path(output_dir).resolve()
    output_dir.mkdir(parents=True, exist_ok=True)

    root_dir = Path(__file__).resolve().parent.parent

    generate_hotdoc_includes(root_dir, output_dir)
    generate_wrapdb_table(output_dir)

    if dummy_output_file:
        with open(output_dir/dummy_output_file, 'w', encoding='utf-8') as f:
            f.write('dummy file for custom_target output')

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Generate meson docs')
    parser.add_argument('--output-dir', required=True)
    parser.add_argument('--dummy-output-file', type=str)

    args = parser.parse_args()

    regenerate_docs(output_dir=args.output_dir,
                    dummy_output_file=args.dummy_output_file)
