#!/usr/bin/env python3
"""
Build script for creating a single-file executable of the Fixture Manager daemon
using PyInstaller.
"""

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

def run_command(cmd, cwd=None):
    """Run a command and return the result"""
    print(f"Running: {' '.join(cmd)}")
    try:
        result = subprocess.run(cmd, cwd=cwd, check=True, capture_output=True, text=True)
        if result.stdout:
            print(result.stdout)
        return True
    except subprocess.CalledProcessError as e:
        print(f"Error: {e}")
        if e.stdout:
            print(f"STDOUT: {e.stdout}")
        if e.stderr:
            print(f"STDERR: {e.stderr}")
        return False

def check_python_version():
    """Check if Python version is compatible"""
    if sys.version_info < (3, 8):
        print("Error: Python 3.8 or higher is required")
        return False
    print(f"Python version: {sys.version}")
    return True

def install_build_dependencies():
    """Install PyInstaller and other build dependencies"""
    print("Installing build dependencies...")
    
    # Install build requirements
    if not run_command([sys.executable, "-m", "pip", "install", "-r", "requirements-build.txt"]):
        print("Failed to install build dependencies")
        return False
    
    # Install runtime requirements
    if not run_command([sys.executable, "-m", "pip", "install", "-r", "requirements.txt"]):
        print("Failed to install runtime dependencies")
        return False
    
    return True

def clean_build_directories():
    """Clean previous build artifacts"""
    print("Cleaning build directories...")
    
    dirs_to_clean = ['build', 'dist', '__pycache__']
    for dir_name in dirs_to_clean:
        if os.path.exists(dir_name):
            shutil.rmtree(dir_name)
            print(f"Removed {dir_name}")
    
    # Clean .pyc files
    for root, dirs, files in os.walk('.'):
        for file in files:
            if file.endswith('.pyc'):
                os.remove(os.path.join(root, file))

def create_hooks_directory():
    """Create PyInstaller hooks for better compatibility"""
    hooks_dir = Path("hooks")
    hooks_dir.mkdir(exist_ok=True)
    
    # Create hook for Flask-SQLAlchemy
    hook_content = '''
from PyInstaller.utils.hooks import collect_all

datas, binaries, hiddenimports = collect_all('flask_sqlalchemy')
hiddenimports += [
    'sqlalchemy.dialects.mysql',
    'sqlalchemy.dialects.mysql.pymysql',
    'sqlalchemy.pool',
    'sqlalchemy.engine.default',
]
'''
    
    with open(hooks_dir / "hook-flask_sqlalchemy.py", "w") as f:
        f.write(hook_content)
    
    # Create hook for pandas
    pandas_hook = '''
from PyInstaller.utils.hooks import collect_all

datas, binaries, hiddenimports = collect_all('pandas')
hiddenimports += [
    'pandas._libs.tslibs.base',
    'pandas._libs.tslibs.ccalendar',
    'pandas._libs.tslibs.dtypes',
    'pandas._libs.tslibs.field_array',
    'pandas._libs.tslibs.nattype',
    'pandas._libs.tslibs.np_datetime',
    'pandas._libs.tslibs.offsets',
    'pandas._libs.tslibs.parsing',
    'pandas._libs.tslibs.period',
    'pandas._libs.tslibs.resolution',
    'pandas._libs.tslibs.strptime',
    'pandas._libs.tslibs.timedeltas',
    'pandas._libs.tslibs.timestamps',
    'pandas._libs.tslibs.timezones',
    'pandas._libs.tslibs.tzconversion',
    'pandas._libs.tslibs.vectorized',
]
'''
    
    with open(hooks_dir / "hook-pandas.py", "w") as f:
        f.write(pandas_hook)

def build_executable():
    """Build the executable using PyInstaller"""
    print("Building executable with PyInstaller...")
    
    # Create hooks directory
    create_hooks_directory()
    
    # Build command
    cmd = [
        sys.executable, "-m", "PyInstaller",
        "--clean",
        "fixture-manager.spec"
    ]
    
    if not run_command(cmd):
        print("PyInstaller build failed")
        return False
    
    return True

def test_executable():
    """Test the built executable"""
    print("Testing the built executable...")
    
    executable_name = "fixture-manager"
    if platform.system() == "Windows":
        executable_name += ".exe"
    
    executable_path = Path("dist") / executable_name
    
    if not executable_path.exists():
        print(f"Executable not found: {executable_path}")
        return False
    
    # Test help command
    cmd = [str(executable_path), "--help"]
    if not run_command(cmd):
        print("Executable test failed")
        return False
    
    print(f"Executable built successfully: {executable_path}")
    print(f"File size: {executable_path.stat().st_size / (1024*1024):.1f} MB")
    
    return True

def create_distribution_package():
    """Create a distribution package with the executable and necessary files"""
    print("Creating distribution package...")
    
    dist_dir = Path("distribution")
    if dist_dir.exists():
        shutil.rmtree(dist_dir)
    
    dist_dir.mkdir()
    
    # Copy executable
    executable_name = "fixture-manager"
    if platform.system() == "Windows":
        executable_name += ".exe"
    
    src_exe = Path("dist") / executable_name
    dst_exe = dist_dir / executable_name
    
    if src_exe.exists():
        shutil.copy2(src_exe, dst_exe)
        # Make executable on Unix systems
        if platform.system() != "Windows":
            os.chmod(dst_exe, 0o755)
    
    # Copy essential files
    files_to_copy = [
        "README.md",
        ".env.example",
        "database/schema.sql",
        "install.sh"
    ]
    
    for file_path in files_to_copy:
        src = Path(file_path)
        if src.exists():
            if src.is_file():
                dst = dist_dir / src.name
                shutil.copy2(src, dst)
            else:
                dst = dist_dir / src.name
                shutil.copytree(src, dst)
    
    # Create a simple run script
    run_script_content = f'''#!/bin/bash
# Fixture Manager Daemon Runner

# Set executable permissions
chmod +x ./{executable_name}

# Run the daemon
./{executable_name} "$@"
'''
    
    run_script = dist_dir / "run.sh"
    with open(run_script, "w") as f:
        f.write(run_script_content)
    
    os.chmod(run_script, 0o755)
    
    # Create Windows batch file
    if platform.system() == "Windows":
        bat_content = f'''@echo off
REM Fixture Manager Daemon Runner
{executable_name} %*
'''
        bat_file = dist_dir / "run.bat"
        with open(bat_file, "w") as f:
            f.write(bat_content)
    
    print(f"Distribution package created in: {dist_dir}")
    return True

def main():
    """Main build process"""
    print("=" * 60)
    print("Fixture Manager - PyInstaller Build Script")
    print("=" * 60)
    
    # Check Python version
    if not check_python_version():
        sys.exit(1)
    
    # Clean previous builds
    clean_build_directories()
    
    # Install dependencies
    if not install_build_dependencies():
        print("Failed to install dependencies")
        sys.exit(1)
    
    # Build executable
    if not build_executable():
        print("Build failed")
        sys.exit(1)
    
    # Test executable
    if not test_executable():
        print("Executable test failed")
        sys.exit(1)
    
    # Create distribution package
    if not create_distribution_package():
        print("Failed to create distribution package")
        sys.exit(1)
    
    print("=" * 60)
    print("Build completed successfully!")
    print("=" * 60)
    print("Distribution files are in the 'distribution' directory")
    print("You can now distribute the single executable file.")
    print("=" * 60)

if __name__ == "__main__":
    main()