#!/usr/bin/env python3
# =============================================================================
#  installer/build_usb.py — Build a USB pendrive installer image
# =============================================================================
#
#  Developer tool that:
#    1. Builds the Flutter Windows release (optional — skip with --no-flutter)
#    2. Copies AR-ECDIS and AR-Autopilot binaries into dist/packages/
#    3. Generates a fresh serial number and writes serial.key
#    4. Creates autorun.inf and START_INSTALLER.bat
#
#  Output: dist/  directory ready to be copied to a USB pendrive.
#
#  Prerequisites (on the build machine):
#    - Flutter SDK in PATH  (for AR-Autopilot Display)
#    - Python 3.11+
#    - AR-ECDIS webecdis cloned next to AR-Autopilot (or set --ecdis-dir)
#    - PyInstaller (pip install pyinstaller) — for AR-ECDIS .exe packaging
#
#  Usage:
#    cd installer
#    python build_usb.py --vessel "BUQUE NORTE" --csv ../serials_log.csv
#    python build_usb.py --no-flutter --no-ecdis   # quick test build
# =============================================================================

from __future__ import annotations

import argparse
import shutil
import subprocess
import sys
from pathlib import Path

REPO_ROOT     = Path(__file__).resolve().parent.parent
DISPLAY_DIR   = REPO_ROOT / "display"
INSTALLER_SRC = Path(__file__).resolve().parent / "src"
DIST_DIR      = Path(__file__).resolve().parent / "dist"

# Default location for the AR-ECDIS repo (sibling of AR-Autopilot)
DEFAULT_ECDIS  = REPO_ROOT.parent / "AR ECDIS" / "webecdis"


def run(cmd: list[str], cwd: Path | None = None, check: bool = True):
    print(f"  $ {' '.join(str(c) for c in cmd)}")
    subprocess.run(cmd, cwd=cwd, check=check)


# ---------------------------------------------------------------------------
#  Step 1 — Flutter Windows build
# ---------------------------------------------------------------------------

def build_flutter(flutter_cmd: str = "flutter") -> Path:
    """Build AR-Autopilot Display for Windows and return the build output dir."""
    print("\n[1/5] Building Flutter (Windows release)…")
    run([flutter_cmd, "build", "windows", "--release"], cwd=DISPLAY_DIR)
    build_out = DISPLAY_DIR / "build" / "windows" / "x64" / "runner" / "Release"
    if not build_out.exists():
        raise FileNotFoundError(f"Flutter build output not found: {build_out}")
    print(f"      Output: {build_out}")
    return build_out


# ---------------------------------------------------------------------------
#  Step 2 — AR-ECDIS PyInstaller build
# ---------------------------------------------------------------------------

def build_ecdis(ecdis_dir: Path) -> Path:
    """Package AR-ECDIS with PyInstaller and return the dist directory."""
    print("\n[2/5] Building AR-ECDIS (PyInstaller)…")
    if not ecdis_dir.exists():
        print(f"      AR-ECDIS dir not found ({ecdis_dir}) — skipping.")
        return Path()

    main_py = ecdis_dir / "main.py"
    if not main_py.exists():
        print(f"      AR-ECDIS main.py not found — skipping.")
        return Path()

    run(
        [
            sys.executable, "-m", "PyInstaller",
            "--onedir",
            "--name", "AR-ECDIS",
            "--windowed",
            "--clean",
            str(main_py),
        ],
        cwd=ecdis_dir,
        check=False,    # non-fatal — missing PyInstaller is warned, not fatal
    )
    out = ecdis_dir / "dist" / "AR-ECDIS"
    if out.exists():
        print(f"      Output: {out}")
    else:
        print("      PyInstaller output not found — AR-ECDIS skipped.")
        out = Path()
    return out


# ---------------------------------------------------------------------------
#  Step 3 — Assemble dist/ tree
# ---------------------------------------------------------------------------

def assemble_dist(
    flutter_build: Path,
    ecdis_build: Path,
    serial: str,
) -> None:
    print("\n[3/5] Assembling USB installer tree…")

    # Clean previous dist
    if DIST_DIR.exists():
        shutil.rmtree(DIST_DIR)
    DIST_DIR.mkdir(parents=True)

    # Copy installer source files
    pkg_installer = DIST_DIR
    shutil.copytree(INSTALLER_SRC, pkg_installer / "src")

    # Place the serial key
    (DIST_DIR / "serial.key").write_text(serial, encoding="utf-8")

    # Copy app packages
    packages = DIST_DIR / "packages"
    packages.mkdir()

    if flutter_build.exists():
        dest = packages / "AR-Autopilot"
        shutil.copytree(flutter_build, dest)
        print(f"      AR-Autopilot → packages/AR-Autopilot/")

    if ecdis_build.exists():
        dest = packages / "AR-ECDIS"
        shutil.copytree(ecdis_build, dest)
        print(f"      AR-ECDIS     → packages/AR-ECDIS/")

    print(f"      Serial key   → serial.key ({serial})")


# ---------------------------------------------------------------------------
#  Step 4 — Write autorun + launcher batch
# ---------------------------------------------------------------------------

def write_autorun() -> None:
    print("\n[4/5] Writing autorun.inf and START_INSTALLER.bat…")

    autorun = (
        "[autorun]\n"
        "label=AR Electronics Installer\n"
        "open=START_INSTALLER.bat\n"
        "icon=src\\install.py,0\n"
    )
    (DIST_DIR / "autorun.inf").write_text(autorun, encoding="utf-8")

    batch = (
        "@echo off\n"
        "title AR Electronics — Instalador J6412\n"
        'echo Iniciando instalador AR Electronics...\n'
        'cd /d "%~dp0"\n'
        "python src\\install.py\n"
        "if errorlevel 1 (\n"
        "    echo.\n"
        "    echo ERROR: La instalacion fallo.\n"
        "    pause\n"
        ")\n"
    )
    (DIST_DIR / "START_INSTALLER.bat").write_text(batch, encoding="utf-8")

    # README for field technicians
    readme = (
        "=== AR Electronics — Instalador J6412 ===\n\n"
        "1. Conecte este pendrive al mini PC J6412.\n"
        "2. Abra el explorador de archivos y ejecute START_INSTALLER.bat.\n"
        "   (Si Windows pregunta, elija 'Más información' → 'Ejecutar de todas formas'.)\n"
        "3. El instalador solicitará permisos de administrador — acepte.\n"
        "4. Pulse INSTALAR y espere a que finalice.\n"
        "5. Reinicie el equipo.\n\n"
        "El sistema requiere conexión a internet para la activación de la licencia.\n\n"
        "Soporte: soporte@arelectronics.com\n"
    )
    (DIST_DIR / "LEAME.txt").write_text(readme, encoding="utf-8")


# ---------------------------------------------------------------------------
#  Step 5 — Summary
# ---------------------------------------------------------------------------

def print_summary(serial: str) -> None:
    print("\n[5/5] Build complete.")
    print(f"\n  Directorio de salida : {DIST_DIR}")
    print(f"  Número de serie      : {serial}")
    size_mb = sum(f.stat().st_size for f in DIST_DIR.rglob("*") if f.is_file()) / 1e6
    print(f"  Tamaño total         : {size_mb:.1f} MB")
    print("\n  Copie todo el contenido de dist/ al pendrive USB.")
    print("  Asegúrese de que el pendrive tenga al menos 2 GB de espacio.\n")


# ---------------------------------------------------------------------------
#  Main
# ---------------------------------------------------------------------------

def main():
    parser = argparse.ArgumentParser(
        description="AR Electronics — USB installer builder"
    )
    parser.add_argument("--vessel", default="",
                        help="Vessel name to tag the serial number with")
    parser.add_argument("--csv",
                        help="Path to serials CSV log (created or appended)")
    parser.add_argument("--ecdis-dir", type=Path, default=DEFAULT_ECDIS,
                        help=f"Path to AR-ECDIS webecdis directory (default: {DEFAULT_ECDIS})")
    parser.add_argument("--flutter", default="flutter",
                        help="flutter command (default: 'flutter')")
    parser.add_argument("--no-flutter", action="store_true",
                        help="Skip Flutter build (use existing build output)")
    parser.add_argument("--no-ecdis", action="store_true",
                        help="Skip AR-ECDIS PyInstaller build")
    parser.add_argument("--serial",
                        help="Use an existing serial number instead of generating one")
    args = parser.parse_args()

    print("=" * 60)
    print("  AR Electronics — USB Installer Builder")
    print("=" * 60)

    # Resolve serial
    if args.serial:
        serial = args.serial
        print(f"\n  Using existing serial: {serial}")
    else:
        # Import here to avoid circular issues if running as a module
        sys.path.insert(0, str(Path(__file__).resolve().parent))
        from serial_generator import generate_batch, write_csv  # noqa: PLC0415

        records = generate_batch(1, vessel=args.vessel)
        serial = records[0]["serial"]
        print(f"\n  Generated serial: {serial}")
        if args.csv:
            write_csv(records, args.csv)

    # Flutter build
    if args.no_flutter:
        flutter_build = DISPLAY_DIR / "build" / "windows" / "x64" / "runner" / "Release"
        print(f"\n[1/5] Skipping Flutter build — using {flutter_build}")
    else:
        flutter_build = build_flutter(args.flutter)

    # AR-ECDIS build
    if args.no_ecdis:
        ecdis_build = Path()
        print("\n[2/5] Skipping AR-ECDIS build.")
    else:
        ecdis_build = build_ecdis(args.ecdis_dir)

    # Assemble
    assemble_dist(flutter_build, ecdis_build, serial)
    write_autorun()
    print_summary(serial)


if __name__ == "__main__":
    main()
