# Hermes Node Protocol
# Copyright (c) 2026 Stefy (nextime) Lanza <stefy@nexlab.net>
# All rights reserved.
# 
# This software is released under the MIT License with a copyleft clause.
# See the LICENSE file for full terms.
# Hermes Node Agent — Windows Build Script
# Builds the Windows installer package using PyInstaller and Inno Setup
# 
# Prerequisites:
#   - Python 3.9+ with pip
#   - PyInstaller: pip install pyinstaller
#   - Inno Setup 6: https://jrsoftware.org/isdl.php
#   - NSSM: https://nssm.cc/download (place nssm.exe in windows/ folder)
#
# Usage:
#   cd hermes-node-protocol
#   python windows/build.py

import os
import sys
import shutil
import subprocess
from pathlib import Path

# ── Configuration ────────────────────────────────────────────────────────────
PROJECT_ROOT = Path(__file__).parent.parent
WINDOWS_DIR = PROJECT_ROOT / 'windows'
NODE_AGENT_DIR = PROJECT_ROOT / 'node-agent'
DIST_DIR = WINDOWS_DIR / 'dist'
BUILD_DIR = WINDOWS_DIR / 'build'

AGENT_SCRIPT = NODE_AGENT_DIR / 'hermes_node_agent.py'
MANAGER_SCRIPT = WINDOWS_DIR / 'agent-manager.py'
INSTALLER_SCRIPT = WINDOWS_DIR / 'installer.iss'

PYINSTALLER_AGENT_SPEC = WINDOWS_DIR / 'agent.spec'
PYINSTALLER_MANAGER_SPEC = WINDOWS_DIR / 'manager.spec'

INNO_SETUP_COMPILER = r'C:\Program Files (x86)\Inno Setup 6\ISCC.exe'

# ── Step 1: Clean previous builds ───────────────────────────────────────────
def clean():
    print("[1/5] Cleaning previous builds...")
    for d in [DIST_DIR, BUILD_DIR]:
        if d.exists():
            shutil.rmtree(d)
            print(f"  Removed: {d}")
    DIST_DIR.mkdir(parents=True, exist_ok=True)
    BUILD_DIR.mkdir(parents=True, exist_ok=True)
    print("  ✓ Clean complete")

# ── Step 2: Install Python dependencies ─────────────────────────────────────
def install_deps():
    print("[2/5] Installing Python dependencies...")
    deps = ['websockets', 'pyinstaller', 'pystray', 'pillow', 'wxpython', 'win10toast']
    for dep in deps:
        print(f"  Installing {dep}...")
        subprocess.run([sys.executable, '-m', 'pip', 'install', '--quiet', dep], check=True)
    print("  ✓ Dependencies installed")

# ── Step 3: Build executables with PyInstaller ──────────────────────────────
def build_executables():
    print("[3/5] Building executables with PyInstaller...")
    
    # Build agent executable
    print("  Building hermes-node-agent.exe...")
    subprocess.run([
        'pyinstaller',
        '--onefile',
        '--name', 'hermes-node-agent',
        '--distpath', str(DIST_DIR),
        '--workpath', str(BUILD_DIR / 'agent'),
        '--specpath', str(WINDOWS_DIR),
        '--console',
        '--icon', str(WINDOWS_DIR / 'icon.ico') if (WINDOWS_DIR / 'icon.ico').exists() else 'NONE',
        str(AGENT_SCRIPT)
    ], check=True, cwd=str(PROJECT_ROOT))
    
    # Build manager GUI executable
    print("  Building hermes-node-manager.exe...")
    subprocess.run([
        'pyinstaller',
        '--onefile',
        '--name', 'hermes-node-manager',
        '--distpath', str(DIST_DIR),
        '--workpath', str(BUILD_DIR / 'manager'),
        '--specpath', str(WINDOWS_DIR),
        '--windowed',  # No console window
        '--icon', str(WINDOWS_DIR / 'icon.ico') if (WINDOWS_DIR / 'icon.ico').exists() else 'NONE',
        str(MANAGER_SCRIPT)
    ], check=True, cwd=str(PROJECT_ROOT))
    
    print("  ✓ Executables built")

# ── Step 4: Download NSSM if missing ────────────────────────────────────────
def check_nssm():
    print("[4/5] Checking for NSSM...")
    nssm_path = WINDOWS_DIR / 'nssm.exe'
    if not nssm_path.exists():
        print("  ⚠️  NSSM not found. Download from https://nssm.cc/download")
        print(f"     Place nssm.exe in: {WINDOWS_DIR}")
        print("     (64-bit version recommended)")
        return False
    print(f"  ✓ NSSM found: {nssm_path}")
    return True

# ── Step 5: Build installer with Inno Setup ─────────────────────────────────
def build_installer():
    print("[5/5] Building installer with Inno Setup...")
    
    if not Path(INNO_SETUP_COMPILER).exists():
        print(f"  ⚠️  Inno Setup not found at: {INNO_SETUP_COMPILER}")
        print("     Download from: https://jrsoftware.org/isdl.php")
        print("     Or adjust INNO_SETUP_COMPILER path in this script")
        return False
    
    # Run Inno Setup compiler
    subprocess.run([
        INNO_SETUP_COMPILER,
        str(INSTALLER_SCRIPT)
    ], check=True, cwd=str(WINDOWS_DIR))
    
    print("  ✓ Installer built")
    
    # Find output
    output_dir = WINDOWS_DIR / 'Output'
    if output_dir.exists():
        installers = list(output_dir.glob('*.exe'))
        if installers:
            print(f"\n✅ Installer ready: {installers[0]}")
            return True
    
    print("  ⚠️  Installer output not found")
    return False

# ── Main ─────────────────────────────────────────────────────────────────────
def main():
    print("=== Hermes Node Agent — Windows Build Script ===\n")
    
    # Verify we're on Windows
    if sys.platform not in ('win32', 'cygwin'):
        print("❌ This script must be run on Windows")
        sys.exit(1)
    
    # Verify project structure
    if not AGENT_SCRIPT.exists():
        print(f"❌ Agent script not found: {AGENT_SCRIPT}")
        sys.exit(1)
    
    if not MANAGER_SCRIPT.exists():
        print(f"❌ Manager script not found: {MANAGER_SCRIPT}")
        sys.exit(1)
    
    try:
        clean()
        install_deps()
        build_executables()
        
        if not check_nssm():
            print("\n⚠️  Build incomplete: NSSM missing")
            print("   Download NSSM and re-run this script")
            sys.exit(1)
        
        if build_installer():
            print("\n✅ Build complete!")
            print("\nNext steps:")
            print("  1. Test the installer on a clean Windows VM")
            print("  2. Distribute: windows/Output/hermes-node-agent-installer.exe")
        else:
            print("\n⚠️  Installer build failed")
            print("   Executables are available in: windows/dist/")
            sys.exit(1)
    
    except subprocess.CalledProcessError as e:
        print(f"\n❌ Build failed: {e}")
        sys.exit(1)
    except KeyboardInterrupt:
        print("\n\n⚠️  Build cancelled by user")
        sys.exit(1)

if __name__ == '__main__':
    main()
