# -*- mode: python ; coding: utf-8 -*-
"""
PyInstaller spec file for Kiwy Signage Player (Windows .exe)

Build command (from windows/ directory):
    pyinstaller build.spec --clean --noconfirm

OR use the build script:
    build_win.bat
"""

import os
import sys
from pathlib import Path

# --- Paths -----------------------------------------------------------
# This spec file is in windows/build.spec, so the project root is
# always two levels up from this file's real location.
# __file__ may not be available in PyInstaller spec context fallback to cwd.
try:
    _spec_dir = Path(__file__).resolve().parent
except NameError:
    _spec_dir = Path(os.getcwd()).resolve()
# _spec_dir is now the absolute path to the windows/ directory
BUILD_DIR = _spec_dir
ROOT_DIR = BUILD_DIR.parent
SRC_DIR = ROOT_DIR / 'src'
CONFIG_DIR = ROOT_DIR / 'config'
RESOURCES_DIR = CONFIG_DIR / 'resources'

# --- Determine hidden imports that PyInstaller might miss -------------
hidden_imports = [
    # Kivy core modules
    'kivy.core.window',
    'kivy.core.video',
    'kivy.core.audio',
    'kivy.core.text',
    'kivy.core.image',
    'kivy.core.gl',
    'kivy.core.camera',
    'kivy.core.clipboard',
    'kivy.core.spelling',
    'kivy.core.text.markup',
    'kivy.core.window.window_sdl2',
    'kivy.core.image.img_sdl2',
    'kivy.core.video.video_ffpyplayer',
    'kivy.core.audio.audio_ffpyplayer',
    # Kivy modules
    'kivy.uix.video',
    'kivy.uix.vkeyboard',
    'kivy.uix.popup',
    'kivy.uix.image',
    'kivy.uix.button',
    'kivy.uix.label',
    'kivy.uix.textinput',
    'kivy.uix.boxlayout',
    'kivy.uix.floatlayout',
    'kivy.uix.slider',
    'kivy.uix.widget',
    'kivy.uix.checkbox',
    'kivy.graphics',
    'kivy.graphics.texture',
    'kivy.graphics.vertex_instructions',
    'kivy.graphics.context_instructions',
    'kivy.clock',
    'kivy.loader',
    'kivy.animation',
    'kivy.lang',
    'kivy.logger',
    'kivy.config',
    'kivy.properties',
    'kivy.metrics',
    'kivy.factory',
    # Graphics providers
    'kivy.graphics.opengl',
    'kivy.graphics.opengl_utils',
    'kivy.graphics.fbo',
    'kivy.graphics.gl_instructions',
    'kivy.graphics.stencil_instructions',
    'kivy.graphics.scissor_instructions',
    'kivy.graphics.buffer',
    'kivy.graphics.vbo',
    'kivy.graphics.shader',
    'kivy.graphics.compiler',
    # ffpyplayer
    'ffpyplayer',
    'ffpyplayer.player',
    'ffpyplayer.pic',
    'ffpyplayer.writer',
    # Networking
    'requests',
    'aiohttp',
    'urllib3',
    'certifi',
    'bcrypt',
    # Platform
    'ctypes',
    'ctypes.wintypes',
    'subprocess',
    'shutil',
    'glob',
    'selectors',
    'tempfile',
]

# Exclude Linux-only modules
excluded_imports = [
    'gi',  # GTK introspection (Linux)
    'gi.repository',
    'evdev',  # We inject a fake evdev module in run_win.py
]

# --- Application data files to bundle --------------------------------
# Resources (icons, intro video, etc.)
resources_data = []
for item in RESOURCES_DIR.iterdir():
    if item.is_file():
        target_dir = 'config/resources'
        resources_data.append((str(item), target_dir))

# Config directory (app_config.json)
config_data = []
config_file = CONFIG_DIR / 'app_config.json'
if config_file.exists():
    config_data.append((str(config_file), 'config'))

# Source files - .kv file
kv_file = SRC_DIR / 'signage_player.kv'
kv_data = []
if kv_file.exists():
    kv_data.append((str(kv_file), '.'))

# Bundle the entire src directory as a tree
source_tree = Tree(str(SRC_DIR), prefix='', excludes=['*.pyc', '__pycache__', '*.ini'])

# --- Collect binary DLLs from kivy_deps and ffpyplayer ----------------
import importlib.util
from pathlib import Path as _Path

def _find_share_dlls(package_path, subdir='bin'):
    """Find .dll files under a package's share/ directory."""
    if not package_path:
        return []
    base = _Path(package_path).parent
    # Check: share/<pkg>/bin/ relative to parent
    share = base / 'share'
    if share.is_dir():
        results = []
        for root, dirs, files in os.walk(share):
            for f in files:
                if f.endswith('.dll'):
                    results.append((os.path.join(root, f), '.'))
        return results
    return []

# SDL2 DLLs
_sdl2_spec = importlib.util.find_spec('kivy_deps.sdl2')
_sdl2_dlls = _find_share_dlls(_sdl2_spec.origin if _sdl2_spec else None)

# ANGLE DLLs
_angle_spec = importlib.util.find_spec('kivy_deps.angle')
_angle_dlls = _find_share_dlls(_angle_spec.origin if _angle_spec else None)

# GLEW DLLs
_glew_spec = importlib.util.find_spec('kivy_deps.glew')
_glew_dlls = _find_share_dlls(_glew_spec.origin if _glew_spec else None)

# ffpyplayer FFmpeg DLLs
_ffpy_spec = importlib.util.find_spec('ffpyplayer')
_ffpy_dlls = _find_share_dlls(_ffpy_spec.origin if _ffpy_spec else None)

_all_binaries = _sdl2_dlls + _angle_dlls + _glew_dlls + _ffpy_dlls

if not _all_binaries:
    print("=" * 70)
    print("WARNING: No Kivy/ffpyplayer DLLs found via share/ directories.")
    print("PyInstaller may still auto-detect them, but if the .exe")
    print("fails with 'SDL2.dll not found' or similar, you will need")
    print("to manually add the DLL paths to the spec file.")
    print("=" * 70)

# --- Build the .exe --------------------------------------------------
a = Analysis(
    ['run_win.py'],                         # Entry point (relative to this spec)
    pathex=[str(BUILD_DIR), str(SRC_DIR)],  # Where to find modules
    binaries=_all_binaries,
    datas=resources_data + config_data + kv_data,
    hiddenimports=hidden_imports,
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[str(BUILD_DIR / 'pyi_runtime_hook.py')],
    excludes=excluded_imports,
    noarchive=False,
    module_collection_mode={
        'kivy': 'pyz',
        'kivy.core': 'pyz',
        'kivy.uix': 'pyz',
        'kivy.graphics': 'pyz',
    },
)

# Add the source tree (main.py, etc.)
a.datas += source_tree

pyz = PYZ(a.pure)

exe = EXE(
    pyz,
    a.scripts,
    a.binaries,
    a.zipfiles,
    a.datas,
    [],
    name='KiwySignagePlayer',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    upx_exclude=[],
    runtime_tmpdir=None,
    console=True,           # Show console for debugging startup errors
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
    icon=str(RESOURCES_DIR / 'app_icon.ico') if (RESOURCES_DIR / 'app_icon.ico').exists() else None,
)

# --- COLLECT everything into a single folder -------------------------
coll = COLLECT(
    exe,
    a.binaries,
    a.zipfiles,
    a.datas,
    strip=False,
    upx=True,
    upx_exclude=[],
    name='KiwySignagePlayer',
)
