#!/usr/bin/env python3
"""
Bigg Adventure EQEmu Server - Server-side Manifest Generator
Scans the 'patch_files' directory, calculates SHA-256 hashes & file sizes,
and outputs 'patch_manifest.json' for the Client Patcher.
"""

import os
import json
import hashlib

PATCH_FILES_DIR = os.path.join(os.path.dirname(__file__), "patch_files")
MANIFEST_PATH = os.path.join(os.path.dirname(__file__), "patch_manifest.json")

# Client files the patcher moves into <client>/_retired/<date>/ (never deletes). bazaar.eqg must go so the
# client draws the old Luclin Bazaar from bazaar.s3d, like THJ's client (2026-09-27).
RETIRE = ["bazaar.eqg", "Bazaar.eqg",
          # early UI attempt, never included by EQUI.xml (2026-09-27)
          "uifiles/default/EQUI_SpellDisplayWindow.xml"]

def get_sha256(filepath):
    sha256 = hashlib.sha256()
    with open(filepath, 'rb') as f:
        while chunk := f.read(65536):
            sha256.update(chunk)
    return sha256.hexdigest()

def read_news():
    """Patcher news / patch notes: news.txt next to this script (shown in the patcher log), else the welcome line."""
    path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "news.txt")
    try:
        with open(path, encoding="utf-8") as f:
            text = f.read().strip()
        if text:
            return text
    except OSError:
        pass
    return "Welcome to Bigg's Adventure, a private emulated realm. By invitation only."

def read_patcher_info():
    """Current Windows patcher (patcher_version.txt next to this script, e.g. 3.3): patcher 3.2+ shows a
    "new patcher available" dialog with the website Downloads page when its own version is older, and 3.3+
    replaces itself with patcher_exe/BiggsAdventurePatcher.exe, whose version MUST equal patcher_version.txt."""
    path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "patcher_version.txt")
    try:
        with open(path, encoding="utf-8") as f:
            version = f.read().strip()
    except OSError:
        return None
    if not version:
        return None
    info = {"version": version, "url": "/downloads"}
    # Patcher 3.3+ updates itself from this exe (served by the website at /patch/patcher/BiggsAdventurePatcher.exe,
    # outside patch_files/ so older patchers never download it as a client file).
    exe = os.path.join(os.path.dirname(os.path.abspath(__file__)), "patcher_exe", "BiggsAdventurePatcher.exe")
    if os.path.isfile(exe):
        info.update(exe_url="/patch/patcher/BiggsAdventurePatcher.exe", sha256=get_sha256(exe),
                    size=os.path.getsize(exe))
    else:
        print(f"WARNING: {exe} missing: patchers will not self-update")
    return info

def generate_manifest():
    if not os.path.exists(PATCH_FILES_DIR):
        os.makedirs(PATCH_FILES_DIR, exist_ok=True)
        print(f"Created directory: {PATCH_FILES_DIR}")

    manifest = {
        "version": "1.0.0",
        "server_name": "Bigg Adventure",
        # Read only by the legacy heroes_journey_patcher.py; bigg_adventure_patcher.py logs
        # into whichever patch server it reached. biggs-adventure.duckdns.org is stale.
        "eqhost": "Host=play.biggsadventure.com:5999",
        "news": read_news(),
        "files": [],
        "retire": RETIRE
    }
    patcher = read_patcher_info()
    if patcher:
        manifest["patcher"] = patcher

    print("Scanning patch files...")
    for root, _, files in os.walk(PATCH_FILES_DIR):
        for file in files:
            full_path = os.path.join(root, file)
            rel_path = os.path.relpath(full_path, PATCH_FILES_DIR).replace("\\", "/")
            sha256_hash = get_sha256(full_path)
            size_bytes = os.path.getsize(full_path)
            
            manifest["files"].append({
                "path": rel_path,
                "sha256": sha256_hash,
                "size": size_bytes
            })
            print(f"  + Added: {rel_path} ({size_bytes} bytes, hash: {sha256_hash[:8]}...)")

    with open(MANIFEST_PATH, "w") as f:
        json.dump(manifest, f, indent=2)

    print(f"\nManifest successfully generated at: {MANIFEST_PATH}")
    print(f"Total files: {len(manifest['files'])}")

if __name__ == "__main__":
    generate_manifest()
