#!/usr/bin/env bash
set -euo pipefail

# Cross-build Windows distribution on Linux
# Usage: ./build-dist-windows.sh [VERSION]

source "$(dirname "$0")/build-common.sh"

detect_version "${1:-}"
echo "Building Media Server v${VERSION_CLEAN} for Windows"

# --- Configuration ---
PYTHON_VERSION="3.11.9"
PYTHON_SHORT="311"
DIST_DIR="dist/media-server"
WHEEL_DIR="build/win-wheels"
SITE_PACKAGES="${DIST_DIR}/python/Lib/site-packages"
BUILD_OUTPUT="build/MediaServer-v${VERSION_CLEAN}-win-x64"

clean_dist "${DIST_DIR}" "${WHEEL_DIR}" "${SITE_PACKAGES}"

# --- Download embedded Python (cache-friendly) ---
mkdir -p build
if [ ! -f build/python-embed.zip ]; then
    echo "Downloading embedded Python ${PYTHON_VERSION}..."
    curl -sL "https://www.python.org/ftp/python/${PYTHON_VERSION}/python-${PYTHON_VERSION}-embed-amd64.zip" \
        -o build/python-embed.zip
else
    echo "Using cached embedded Python ${PYTHON_VERSION}"
fi
unzip -qo build/python-embed.zip -d "${DIST_DIR}/python"

# Patch ._pth to enable site-packages and app source
PTH_FILE=$(ls "${DIST_DIR}"/python/python*._pth | head -1)
sed -i 's/^#\s*import site/import site/' "$PTH_FILE"
echo 'Lib\site-packages' >> "$PTH_FILE"
echo '..\app' >> "$PTH_FILE"

# --- Download Windows wheels ---
echo "Downloading Windows wheels..."

# Core dependencies
# NOTE: uvicorn[standard] pulls in uvloop via `sys_platform != 'win32'` marker.
# pip evaluates env markers against the HOST (Linux in CI), so uvloop is
# requested, but `--platform win_amd64 --only-binary :all:` cannot find a
# Windows wheel for uvloop (none exist). Result: pip backtracks across every
# uvicorn[standard] version and ResolutionImpossible. Fix: use plain uvicorn
# and list only the Windows-compatible standard extras we actually need.
CORE_DEPS=(
    "fastapi>=0.109.0"
    "uvicorn>=0.27.0"
    "httptools>=0.5.0"
    "websockets>=10.4"
    "python-dotenv>=0.13"
    "pydantic>=2.0"
    "pydantic-settings>=2.0"
    "pyyaml>=6.0"
    "mutagen>=1.47.0"
    "pillow>=10.0.0"
)

# Windows-specific dependencies
# NOTE: wmi is a transitive dep of screen-brightness-control gated on
# `platform_system == "Windows"`. pip evaluates env markers against the HOST
# (Linux in CI), so it gets skipped during cross-build. Listed explicitly here
# so the wheel actually lands in the Windows bundle. Same gotcha as the
# uvicorn[standard]/uvloop case documented above.
WIN_DEPS=(
    "winsdk>=1.0.0b10"
    "pywin32>=306"
    "comtypes>=1.2.0"
    "pycaw>=20230407"
    "screen-brightness-control>=0.20.0"
    "wmi>=1.5.1"
    "monitorcontrol>=3.0.0"
)

# Visualizer dependencies
VIS_DEPS=(
    "soundcard>=0.4.0"
    "numpy>=1.24.0,<2.0"
    # pystray lives here (not WIN_DEPS) so its transitive Pillow resolves in the
    # same pass as CORE_DEPS. Keeping it in the per-dep WIN_DEPS loop downloaded
    # a second Pillow version that clobbered the core one on unzip, producing
    # "_imaging extension was built for another version of Pillow" at runtime.
    "pystray>=0.19.0"
)

# Resolve core + visualizer deps in a SINGLE call so pip picks compatible
# transitive versions (notably pydantic/pydantic-core must match).
# Per-dep loops resolve each dep independently and can leave mismatched
# transitive versions that overwrite each other in the site-packages unzip.
CROSS_DEPS=("${CORE_DEPS[@]}" "${VIS_DEPS[@]}")
pip download --quiet --no-cache-dir --dest "$WHEEL_DIR" \
    --platform win_amd64 --python-version "${PYTHON_SHORT}" \
    --implementation cp --only-binary :all: \
    "${CROSS_DEPS[@]}"

# Windows-only deps in a loop with --pre: winsdk only ships beta wheels
# (1.0.0bNN) and each dep needs its own platform/non-platform fallback.
for dep in "${WIN_DEPS[@]}"; do
    pip download --pre --quiet --no-cache-dir --dest "$WHEEL_DIR" \
        --platform win_amd64 --python-version "${PYTHON_SHORT}" \
        --implementation cp --only-binary :all: \
        "$dep" 2>/dev/null || \
    pip download --pre --quiet --no-cache-dir --dest "$WHEEL_DIR" \
        --only-binary :all: \
        "$dep"
done

# Remove numpy 2.x wheels pulled as transitive deps (soundcard requires <2.0)
for f in "$WHEEL_DIR"/numpy-2*; do
    [ -f "$f" ] && echo "Removing incompatible: $(basename "$f")" && rm "$f"
done

# Install wheels into site-packages
echo "Installing wheels..."
for whl in "$WHEEL_DIR"/*.whl; do
    unzip -qo "$whl" -d "$SITE_PACKAGES"
done

# numpy wheels from PyPI don't include _distributor_init_local.py unless
# patched by delvewheel. In embedded Python, os.add_dll_directory() is never
# called, so libopenblas can't be found and numpy fails to import.
# Generate the missing loader here instead.
if [ -d "${SITE_PACKAGES}/numpy" ]; then
    cat > "${SITE_PACKAGES}/numpy/_distributor_init_local.py" << 'EOF'
import os
import sys
if sys.platform == 'win32':
    _libs = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'numpy.libs'))
    if os.path.isdir(_libs):
        os.add_dll_directory(_libs)
EOF
    echo "Generated numpy/_distributor_init_local.py"
fi

cleanup_site_packages "$SITE_PACKAGES" "pyd" "dll"
verify_frontend
copy_app_files "$DIST_DIR"

# Copy scripts needed for auto-start
mkdir -p "${DIST_DIR}/scripts"
cp scripts/start-hidden.vbs "${DIST_DIR}/scripts/"

# --- Create launcher ---
cat > "${DIST_DIR}/media-server.bat" << 'LAUNCHER'
@echo off
setlocal
set "ROOT=%~dp0"
"%ROOT%python\python.exe" -m media_server.main %*
LAUNCHER

# --- Package ---
echo "Creating archives..."
mkdir -p build

# Portable ZIP
cp -r "${DIST_DIR}" "${BUILD_OUTPUT}"
cd build
zip -qr "MediaServer-v${VERSION_CLEAN}-win-x64.zip" "MediaServer-v${VERSION_CLEAN}-win-x64"
cd ..

echo "Build complete: build/MediaServer-v${VERSION_CLEAN}-win-x64.zip"
echo "Dist directory ready for NSIS: ${DIST_DIR}"
