#!/usr/bin/env python
# License: GPLv3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>


import io
import os
import subprocess
import sys
import tarfile
import time
from urllib.request import Request, urlopen


def printf(*args, **kw):
    print(*args, **kw)
    sys.stdout.flush()


def download_with_retry(url: str | Request, count: int = 5) -> bytes:
    for i in range(count):
        try:
            print('Downloading', getattr(url, 'full_url', url), flush=True)
            with urlopen(url) as f:
                ans: bytes = f.read()
            return ans
        except Exception as err:
            if getattr(err, 'code', -1) == 403:
                raise
            if i >= count - 1:
                raise
            print(f'Download failed with error {err} retrying...', file=sys.stderr)
            time.sleep(1)
    return b''


def sw():
    sw = os.environ['SW']
    os.chdir(sw)
    url = 'https://download.calibre-ebook.com/ci/calibre7/windows-64.tar.xz'
    tarball = download_with_retry(url)
    with tarfile.open(fileobj=io.BytesIO(tarball)) as tf:
        tf.extractall()
    printf('Download complete')


def sanitize_path():
    needed_paths = []
    executables = 'git.exe curl.exe rapydscript.cmd node.exe'.split()
    for p in os.environ['PATH'].split(os.pathsep):
        for x in tuple(executables):
            if os.path.exists(os.path.join(p, x)):
                needed_paths.append(p)
                executables.remove(x)
    sw = os.environ['SW']
    paths = rf'{sw}\private\python\bin {sw}\private\python\Lib\site-packages\pywin32_system32 {sw}\bin {sw}\qt\bin C:\Windows\System32'.split() + needed_paths
    os.environ['PATH'] = os.pathsep.join(paths)
    print('PATH:', os.environ['PATH'])


def python_exe():
    return os.path.join(os.environ['SW'], 'private', 'python', 'python.exe')


def build():
    sanitize_path()
    cmd = [python_exe(), 'setup.py', 'bootstrap', '--ephemeral']
    printf(*cmd)
    p = subprocess.Popen(cmd)
    raise SystemExit(p.wait())


def test():
    sanitize_path()
    # test_rs is flaky in CI because webengine is flaky in CI
    for q in ('test',):
        cmd = [python_exe(), 'setup.py', q]
        printf(*cmd)
        p = subprocess.Popen(cmd)
        if p.wait() != 0:
            raise SystemExit(p.returncode)


def setup_env():
    os.environ['SW'] = SW = r'C:\r\sw64\sw'
    os.makedirs(SW, exist_ok=True)
    os.environ['QMAKE'] = os.path.join(SW, r'qt\bin\qmake')
    os.environ['CALIBRE_QT_PREFIX'] = os.path.join(SW, r'qt')
    os.environ['CI'] = 'true'
    os.environ['OPENSSL_MODULES'] = os.path.join(SW, 'lib', 'ossl-modules')
    os.environ['PIPER_TTS_DIR'] = os.path.join(SW, 'piper')
    os.environ['CALIBRE_ESPEAK_DATA_DIR'] = os.path.join(SW, 'share', 'espeak-ng-data')


def main():
    q = sys.argv[-1]
    setup_env()
    if q == 'bootstrap':
        subprocess.check_call(['rapydscript.cmd', '--version'])
        build()
    elif q == 'test':
        test()
    elif q == 'install':
        sw()
    else:
        if len(sys.argv) == 1:
            raise SystemExit('Usage: win-ci.py sw|build|test')
        raise SystemExit(f'{sys.argv[-1]!r} is not a valid action')


if __name__ == '__main__':
    main()
