#!/usr/bin/env python3

from os.path import join
from subprocess import check_call, check_output
from sys import argv, stdout
from tempfile import TemporaryDirectory

with TemporaryDirectory() as tmpdir:
    check_call(['python3', '-m', 'venv', tmpdir])

    def install_and_list(target):
        check_call([join(tmpdir, 'bin', 'pip'), 'install', target])
        frozen = (
            check_output([join(tmpdir, 'bin', 'pip'), 'freeze'])
            .decode('utf-8')
            .strip()
            .split('\n')
        )
        # file bit skips ourself
        return set(p.split('=', 1)[0] for p in frozen if 'file' not in p)

    # base needs
    frozen = install_and_list('.')
    # dev needs
    dev_frozen = install_and_list('.[dev]') - frozen
    # docs needs
    docs_frozen = install_and_list('.[docs]') - dev_frozen - frozen

    # find the installed version for each package
    versions = {}
    for pv in (
        check_output([join(tmpdir, 'bin', 'pip'), 'freeze'])
        .decode('utf-8')
        .strip()
        .split('\n')
    ):
        if 'file' in pv:
            # skip ourself
            continue
        p, v = pv.split('==')
        versions[p] = (v,)


# special handling for older python versions due to libraries dropping support
# early
versions['alabaster'] = (
    "0.7.16; python_version<'3.10'",
    f"{versions['alabaster'][0]}; python_version>='3.10'",
)
versions['click'] = (
    "8.1.8; python_version<'3.10'",
    f"{versions['click'][0]}; python_version>='3.10'",
)
versions['myst-parser'] = (
    "3.0.1; python_version<'3.10'",
    f"{versions['myst-parser'][0]}; python_version>='3.10'",
)
versions['Sphinx'] = (
    "7.4.7; python_version=='3.9'",
    "8.1.3; python_version=='3.10'",
    f"{versions['Sphinx'][0]}; python_version>='3.11'",
)
versions['mdit-py-plugins'] = (
    "0.4.2; python_version=='3.9'",
    f"{versions['mdit-py-plugins'][0]}; python_version>='3.10'",
)


def write_packages(fh, packages, header, prefix=''):
    fh.write(header)
    for p in sorted(packages):
        for v in versions[p]:
            fh.write(prefix)
            fh.write(p)
            fh.write('==')
            fh.write(v)
            fh.write('\n')


write_packages(stdout, frozen, header='base\n', prefix='  ')
write_packages(stdout, dev_frozen, header='dev\n', prefix='  ')
write_packages(stdout, docs_frozen, header='docs\n', prefix='  ')

header = f'# DO NOT EDIT THIS FILE DIRECTLY - use {argv[0]} to update\n'

with open('requirements.txt', 'w') as fh:
    write_packages(fh, frozen, header=header)

with open('requirements-dev.txt', 'w') as fh:
    write_packages(fh, dev_frozen, header=header)

with open('requirements-docs.txt', 'w') as fh:
    write_packages(fh, docs_frozen, header=header)
