#!/usr/bin/env python3

import io
import json
import re
import sys
import urllib.request

import yaml

from tortoisehg.util import hgversion


def job_name(name, hgver):
    return f'{name}-hg-{hgver}'


def gen_update_to_mercurial_rev(hgver):
    if hgver in ['stable', 'default']:
        update_to = hgver
    else:
        update_to = rf"""'tag("re:\A{re.escape(hgver)}")'"""
    return [
        'hg -R /ci/repos/mercurial pull https://repo.mercurial-scm.org/hg',
        f'hg -R /ci/repos/mercurial update {update_to}',
        'hg -R /ci/repos/mercurial summary',
    ]


def gen_ensure_mercurial_build(hgver, prebuilt_images):
    if f'hg-{hgver}' in prebuilt_images:
        build = []
    else:
        build = gen_update_to_mercurial_rev(hgver) + [
            'make -C /ci/repos/mercurial local PYTHON=$PYTHON',
        ]
    return build + ['/ci/repos/mercurial/hg version --debug']


def thg_make_command(target):
    return f'make {target} PYTHON=$PYTHON HGPATH=/ci/repos/mercurial'


def gen_gitlab_ci_yml():
    # This was querying https://index.docker.io/v1/repositories/octobus/ci-py3-hgext3rd/tags,
    # which hasn't been maintained.
    prebuilt_images = ['latest']

    hg_releases = []
    for hgver in hgversion.testedwith.decode().split():
        try:
            with urllib.request.urlopen(
                f'https://www.mercurial-scm.org/repo/hg/file/{hgver}rc0'
            ):
                pass
        except urllib.error.HTTPError:
            pass
        else:
            hg_releases.append(hgver)

    variables = {
        'variables': {
            'PYTHON': "python3",
            'THG_CI_IMAGE_TAG': "v2.1"
        },
    }

    tests = {
        job_name('tests', hgver): {
            'script': [
                '$PYTHON -V',
                '$PYTHON -m pip list',
                *gen_ensure_mercurial_build(hgver, prebuilt_images),
                thg_make_command('local'),
                'xvfb-run ' + thg_make_command('tests'),
            ],
            'allow_failure': hgver == 'default',
        }
        for hgver in hg_releases + ['stable', 'default']
    }
    pytype = {
        job_name('pytype', hgver): {
            'script': [
                '$PYTHON -V',
                '$PYTHON -m pip list',
                'pytype --version',
                *gen_ensure_mercurial_build(hgver, prebuilt_images),
                thg_make_command('local'),
                'PYTHON=$PYTHON /ci/repos/mercurial/contrib/setup-pytype.sh',
                # The following is a workaround for pytype's lack of support for
                # custom pyi files (https://github.com/google/pytype/issues/483).
                'ln -svf $(pwd)/contrib/typehints/* '
                '$($PYTHON -c "import pytype; '
                'print(pytype.__path__[0])")/typeshed/stubs/',
                thg_make_command('pytype') + ' PYTHON_VERSION=3.11',
            ],
            'allow_failure': True,
        }
        for hgver in ['stable', 'default']
    }

    image = 'registry.heptapod.net/mercurial/ci-images/thg-pyqt5:$THG_CI_IMAGE_TAG'

    return {'image': image, **variables, **tests, **pytype}


def initstdio():
    # stdio streams on Python 3 are io.TextIOWrapper instances proxying another
    # buffer. These streams will normalize \n to \r\n by default.

    if sys.stdout is not None:
        kwargs = {
            "newline": "\n",
            "line_buffering": sys.stdout.line_buffering,
            "write_through": sys.stdout.write_through
        }

        sys.stdout = io.TextIOWrapper(
            sys.stdout.buffer, sys.stdout.encoding, sys.stdout.errors, **kwargs
        )

    if sys.stderr is not None:
        kwargs = {
            "newline": "\n",
            "line_buffering": sys.stderr.line_buffering,
            "write_through": sys.stderr.write_through
        }

        sys.stderr = io.TextIOWrapper(
            sys.stderr.buffer, sys.stderr.encoding, sys.stderr.errors, **kwargs
        )

    if sys.stdin is not None:
        # No write_through on read-only stream.
        sys.stdin = io.TextIOWrapper(
            sys.stdin.buffer,
            sys.stdin.encoding,
            sys.stdin.errors,
            # None is universal newlines mode.
            newline=None,
            line_buffering=sys.stdin.line_buffering,
        )


if __name__ == '__main__':
    initstdio()
    toplevel = gen_gitlab_ci_yml()
    sys.stdout.write(
        "# This file was generated by contrib/generate_gitlab_ci_yml.py.\n\n"
    )
    yaml.dump(toplevel, sys.stdout, line_break='\n', sort_keys=False)
    sys.stdout.flush()
