#!/bin/bash
# Cross-compile a Windows Python wheel using MinGW inside WSL.
set -e -o pipefail

PYVER=3.10.11
PYVER_SHORT=310

for i in "$@"; do
    case $i in
        -a=*|--arch=*) arch="${i#*=}";;
        *) ;;
    esac
done

if [ "$arch" = "win32" ]; then
    MINGW_HOST=i686-w64-mingw32
    WIN_PLAT=win32
    NUGET_PKG=pythonx86
    MINGW_PKGS="gcc-mingw-w64-i686 g++-mingw-w64-i686 binutils-mingw-w64-i686"
else
    MINGW_HOST=x86_64-w64-mingw32
    WIN_PLAT=win_amd64
    NUGET_PKG=python
    MINGW_PKGS="gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64"
fi

apt-get update -qq
apt-get install -y -qq --no-install-recommends \
    autoconf automake libtool build-essential \
    python3 python3-pip \
    $MINGW_PKGS \
    mingw-w64-tools \
    curl unzip

pip3 install -q --break-system-packages cffi setuptools requests

mkdir -p lib include wheels

# Build libdogecoin for Windows via MinGW (WSL Python can run autogen.sh)
python3 fetch.py --host=$MINGW_HOST

# Get Windows Python headers from NuGet (.nupkg is a zip)
curl -sL "https://www.nuget.org/api/v2/package/$NUGET_PKG/$PYVER" -o python-win.nupkg
unzip -q python-win.nupkg "tools/include/*" -d python-win
PYINC="$(pwd)/python-win/tools/include"
PYLIBDIR="$(pwd)/python-win/libs"
mkdir -p "$PYLIBDIR"

# Generate MinGW import library from the actual python310.dll (embeddable zip).
# python3.def (stable ABI) is missing many symbols CFFI uses; gendef reads all
# real exports from the DLL so the import library is complete.
if [ "$arch" = "win32" ]; then
    EMBED_ZIP="python-${PYVER}-embed-win32.zip"
else
    EMBED_ZIP="python-${PYVER}-embed-amd64.zip"
fi
curl -sL "https://www.python.org/ftp/python/${PYVER}/${EMBED_ZIP}" -o python-embed.zip
unzip -q python-embed.zip python${PYVER_SHORT}.dll
gendef python${PYVER_SHORT}.dll
${MINGW_HOST}-dlltool -D python${PYVER_SHORT}.dll \
    -d python${PYVER_SHORT}.def \
    -l "${PYLIBDIR}/libpython${PYVER_SHORT}.a"
rm python${PYVER_SHORT}.dll python${PYVER_SHORT}.def python-embed.zip

# Emit the CFFI C source (WSL Python generates it; the C itself is version-agnostic)
python3 - <<'PYEOF'
import sys
sys.path.insert(0, 'python')
from _build import ffibuilder
ffibuilder.emit_c_code('_libdogecoin_cffi.c')
PYEOF

# Compile the extension as a Windows PE DLL using MinGW
${MINGW_HOST}-gcc -O2 -shared \
    -I"${PYINC}" \
    -Iinclude \
    -o _libdogecoin_cffi.pyd \
    _libdogecoin_cffi.c \
    lib/libdogecoin.a \
    -L"${PYLIBDIR}" -lpython${PYVER_SHORT} \
    -lws2_32 -lgdi32 -lcrypt32

# Package as a wheel (zip with correct layout and RECORD hashes)
PY_ABI="cp${PYVER_SHORT}"
WHEEL_TAG="${PY_ABI}-${PY_ABI}-${WIN_PLAT}"

python3 - <<PYEOF
import zipfile, hashlib, base64, pathlib, re

root = pathlib.Path(".")
src = (root / "setup.py").read_text()
m = re.search(r'version\s*=\s*[\'"]([^\'"]+)[\'"]', src)
version = m.group(1) if m else "0.1.2"

wheel_tag = "${WHEEL_TAG}"
wheel_name = f"libdogecoin-{version}-{wheel_tag}.whl"
dist_info = f"libdogecoin-{version}.dist-info"

def entry(data: bytes) -> str:
    h = base64.urlsafe_b64encode(hashlib.sha256(data).digest()).rstrip(b"=").decode()
    return f"sha256={h},{len(data)}"

pkg_files = {
    "libdogecoin/__init__.py":          (root / "python" / "libdogecoin" / "__init__.py").read_bytes(),
    "libdogecoin/_cdef.h":              (root / "python" / "libdogecoin" / "_cdef.h").read_bytes(),
    "libdogecoin/_surface.json":        (root / "python" / "libdogecoin" / "_surface.json").read_bytes(),
    "libdogecoin/_libdogecoin_cffi.pyd": (root / "_libdogecoin_cffi.pyd").read_bytes(),
}

wheel_meta = (
    "Wheel-Version: 1.0\n"
    "Generator: bin/init\n"
    "Root-Is-Purelib: false\n"
    f"Tag: {wheel_tag}\n"
)
metadata = (
    "Metadata-Version: 2.1\n"
    f"Name: libdogecoin\n"
    f"Version: {version}\n"
    "Summary: Python interface for the libdogecoin C library\n"
    "License: MIT\n"
    "Requires-Dist: cffi>=1.16\n"
)

records = []
with zipfile.ZipFile(f"wheels/{wheel_name}", "w", zipfile.ZIP_DEFLATED) as zf:
    for arcname, data in pkg_files.items():
        zf.writestr(arcname, data)
        records.append(f"{arcname},{entry(data)}")

    for fname, content in [(f"{dist_info}/WHEEL", wheel_meta), (f"{dist_info}/METADATA", metadata)]:
        data = content.encode()
        zf.writestr(fname, content)
        records.append(f"{fname},{entry(data)}")

    record_str = "\n".join(records) + f"\n{dist_info}/RECORD,,\n"
    zf.writestr(f"{dist_info}/RECORD", record_str)

print(f"Created wheels/{wheel_name}")
PYEOF

rm -rf python-win python-win.nupkg _libdogecoin_cffi.c _libdogecoin_cffi.pyd
