"""
Windows platform startup layer.

Must remain importable before ws_package is on sys.path — only stdlib imports
at module level.
"""
import sys
import os
import shutil
import subprocess
import ctypes
import json
import tempfile
from pathlib import Path


def _paths_same_dir(a: Path, b: Path) -> bool:
    """Return True when two paths refer to the same directory."""
    try:
        return a.resolve().samefile(b.resolve())
    except OSError:
        return os.path.normcase(str(a.resolve())) == os.path.normcase(str(b.resolve()))


def _silent_relaunch_flags() -> int:
    """Process creation flags for a detached silent relaunch."""
    flags = 0x00000008 | 0x00000200  # DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP
    if hasattr(subprocess, "CREATE_NO_WINDOW"):
        flags |= subprocess.CREATE_NO_WINDOW
    return flags


def _ensure_silent_appdata_install(is_silent: bool) -> None:
    """
    Silent mode: always run from %APPDATA%\\Roaming\\Workstatus.

    If the frozen EXE was started from another location (MDM drop folder, installer
    directory, etc.), copy Workstatus.exe, _internal/, and user_token_file.txt into
    AppData, relaunch from there, and exit the current process.

    Must run early (before heavy imports).  Uses only stdlib + optional error_codes.
    """
    if not is_silent:
        return
    if not sys.platform.startswith("win"):
        return
    if not getattr(sys, "frozen", False):
        return

    appdata = os.environ.get("APPDATA", "")
    if not appdata:
        return

    appdata_dir = Path(appdata) / "Workstatus"
    try:
        exe_path = Path(sys.executable).resolve()
    except OSError:
        return
    exe_dir = exe_path.parent

    if _paths_same_dir(exe_dir, appdata_dir):
        return

    internal_src = exe_dir / "_internal"
    if not internal_src.is_dir():
        # Broken onedir — _quarantine_stale_appdata_install should have exited already.
        return

    token_src = _find_user_token_source(exe_dir)
    if not token_src:
        msg = (
            "Workstatus silent install requires user_token_file.txt next to the "
            "executable, in upgrade/, or in the working directory.\n\n"
            f"Started from: {exe_dir}"
        )
        try:
            ctypes.windll.user32.MessageBoxW(0, msg, "Workstatus — Setup Required", 0x10)
        except Exception:  # noqa: BLE001
            pass
        try:
            from ws_package.utils.error_codes import ErrorCode

            print(
                json.dumps({
                    "type": "fatal_error",
                    "data": {
                        "code": str(ErrorCode.TOKEN_FILE_MISSING),
                        "message": msg,
                    },
                }),
                flush=True,
            )
        except Exception:  # noqa: BLE001
            pass
        from ws_package.utils.error_codes import ExitCode
        sys.exit(ExitCode.STARTUP_FAILURE)

    exe_dst = appdata_dir / exe_path.name
    internal_dst = appdata_dir / "_internal"
    token_dst = appdata_dir / "user_token_file.txt"

    try:
        appdata_dir.mkdir(parents=True, exist_ok=True)
        shutil.copy2(exe_path, exe_dst)
        shutil.copytree(internal_src, internal_dst, dirs_exist_ok=True)
        shutil.copy2(token_src, token_dst)
    except OSError as exc:
        msg = (
            "Workstatus could not copy files to AppData.\n\n"
            f"Target: {appdata_dir}\n"
            f"Error: {exc}"
        )
        try:
            ctypes.windll.user32.MessageBoxW(0, msg, "Workstatus — Setup Failed", 0x10)
        except Exception:  # noqa: BLE001
            pass
        from ws_package.utils.error_codes import ExitCode
        sys.exit(ExitCode.STARTUP_FAILURE)

    relaunch_exe = appdata_dir / "Workstatus.exe"
    if not relaunch_exe.is_file():
        relaunch_exe = exe_dst

    try:
        subprocess.Popen(
            [str(relaunch_exe)],
            cwd=str(appdata_dir),
            close_fds=True,
            creationflags=_silent_relaunch_flags(),
        )
    except OSError as exc:
        msg = f"Workstatus could not start from AppData: {exc}"
        try:
            ctypes.windll.user32.MessageBoxW(0, msg, "Workstatus — Launch Failed", 0x10)
        except Exception:  # noqa: BLE001
            pass
        from ws_package.utils.error_codes import ExitCode
        sys.exit(ExitCode.STARTUP_FAILURE)

    sys.exit(0)


def _quarantine_stale_appdata_install() -> None:
    """
    Guard against launching a broken onedir install (missing _internal/).

    Design principle
    ----------------
    The ONLY indicator we check is whether _internal/ exists next to the
    running EXE.  Location (AppData\\Roaming, AppData\\Local, Program Files,
    anywhere else) is irrelevant: Electron installers and electron-builder
    legitimately deploy the Python backend to various directories, including
    inside AppData, and that location can change between product versions.

    Decision table
    --------------
    _internal/ absent  →  broken EXE (stale onefile remnant or partial
                           install).  Show a user-friendly dialog, schedule
                           a detached bat to self-delete after we exit, and
                           call sys.exit(1).  Never try to launch another
                           EXE from here — that is the installer's job.

    _internal/ present →  valid onedir build.  Proceed normally.  As a
                           best-effort courtesy, remove any STALE artifacts
                           (EXEs without an adjacent _internal/) found at
                           the legacy AppData\\Roaming\\Workstatus\\ location
                           so they cannot auto-start on the next login.
                           Never touch AppData\\Roaming if _internal/ is
                           present there — that would destroy a valid
                           deployment living alongside this one.

    Upgrade safety
    --------------
    Upgrades are handled by the installer.  The Python backend makes no
    assumption about install paths across versions.  As long as the new
    EXE has _internal/ next to it, this function is a no-op.
    """
    if not sys.platform.startswith("win"):
        return
    if not getattr(sys, "frozen", False):
        return

    try:
        exe_path = Path(sys.executable).resolve()
    except OSError:
        return
    exe_dir = exe_path.parent

    # ── Primary check: is this EXE part of a complete onedir build? ──────────
    if (exe_dir / "_internal").is_dir():
        # Valid onedir install.  Run the best-effort stale-artifact cleanup
        # for the legacy AppData\Roaming location and return.
        _remove_stale_appdata_artifacts(exe_path)
        return

    # ── _internal/ is absent — this EXE is broken ────────────────────────────
    # Possible causes:
    #   • Old PyInstaller onefile EXE left in AppData\Roaming after migration
    #     to onedir (onefile extracted itself there; _internal never existed)
    #   • Partial/corrupt install where _internal/ was deleted or never copied
    #
    # Action: show a clear error dialog, emit a structured fatal-error JSON
    # (for the Electron parent process), schedule self-deletion, exit.

    msg = (
        "Workstatus cannot start from this location:\n\n"
        f"{exe_path}\n\n"
        "This copy is missing required internal files (_internal/).\n\n"
        "Please reinstall Workstatus using the latest installer."
    )

    try:
        ctypes.windll.user32.MessageBoxW(
            0, msg, "Workstatus — Reinstall Required", 0x10
        )
    except Exception:  # noqa: BLE001 — headless / no display
        pass

    try:
        from ws_package.utils.error_codes import ErrorCode as _EC
        print(json.dumps({
            "type": "fatal_error",
            "data": {
                "code": str(_EC.SETUP_WIN_MISSING_EXE),
                "message": msg,
            },
        }), flush=True)
    except Exception:  # noqa: BLE001
        pass

    # Schedule a detached bat to delete this broken EXE after we exit.
    # We do NOT try to delete _internal/ here because it is absent.
    try:
        bat_lines = [
            "@echo off",
            "setlocal",
            f'set "TARGET={exe_path}"',
            "set /a TRIES=0",
            ":waitloop",
            "timeout /t 1 /nobreak >nul 2>&1",
            'del "%TARGET%" >nul 2>&1',
            'if not exist "%TARGET%" goto done',
            "set /a TRIES+=1",
            "if %TRIES% lss 15 goto waitloop",
            ":done",
            '(goto) 2>nul & del "%~f0"',
        ]
        bat_content = "\r\n".join(bat_lines) + "\r\n"
        with tempfile.NamedTemporaryFile(
            mode="w", suffix="_ws_cleanup.bat", delete=False, encoding="ascii"
        ) as bf:
            bf.write(bat_content)
            cleanup_bat = bf.name
        # DETACHED_PROCESS = 0x00000008, CREATE_NEW_PROCESS_GROUP = 0x00000200
        DETACHED = 0x00000008 | 0x00000200
        subprocess.Popen(
            ["cmd", "/C", cleanup_bat],
            close_fds=True,
            creationflags=DETACHED,
        )
    except Exception:  # noqa: BLE001 — cleanup is best-effort
        pass

    from ws_package.utils.error_codes import ExitCode
    sys.exit(ExitCode.STARTUP_FAILURE)


def _remove_stale_appdata_artifacts(current_exe_path: Path) -> None:
    """
    Best-effort removal of stale EXE artifacts at the legacy
    AppData\\Roaming\\Workstatus\\ location.

    Guards
    ------
    • Only runs when AppData\\Roaming\\Workstatus\\ exists.
    • Does NOTHING if _internal/ is present there — that directory contains
      a valid onedir deployment (e.g. a different install managed by Electron)
      and must not be touched.
    • Only removes the bare EXE and legacy launcher scripts (VBS/LNK).  Never
      recursively deletes directories.
    • Scrubs the HKCU Run key entry only when it still points at the stale
      AppData location.
    """
    appdata = os.environ.get("APPDATA", "")
    if not appdata:
        return

    appdata_ws = Path(appdata) / "Workstatus"
    if not appdata_ws.exists():
        return

    # If _internal/ is present, this is a valid deployment — leave it alone.
    if (appdata_ws / "_internal").is_dir():
        return

    stale_exe = appdata_ws / "Workstatus.exe"
    if not stale_exe.exists():
        # Nothing to clean up.
        return

    # Guard: never delete ourselves (shouldn't be reachable here since we have
    # _internal/, but be explicit).
    try:
        if stale_exe.resolve() == current_exe_path:
            return
    except OSError:
        return

    startup_dir = (
        Path(appdata)
        / "Microsoft"
        / "Windows"
        / "Start Menu"
        / "Programs"
        / "Startup"
    )
    for tgt in (
        stale_exe,
        appdata_ws / "Workstatus.vbs",
        startup_dir / "Workstatus.lnk",
        startup_dir / "Workstatus.vbs",
    ):
        try:
            if tgt.is_file():
                tgt.unlink()
        except OSError:
            pass  # Held open by something; non-fatal.

    # Scrub stale Registry Run entry if it still references AppData\Roaming.
    try:
        import winreg  # stdlib on Windows
        with winreg.OpenKey(
            winreg.HKEY_CURRENT_USER,
            r"Software\Microsoft\Windows\CurrentVersion\Run",
            0, winreg.KEY_READ | winreg.KEY_SET_VALUE,
        ) as run_key:
            try:
                existing, _ = winreg.QueryValueEx(run_key, "Workstatus")
                if existing and str(appdata_ws).lower() in existing.lower():
                    winreg.DeleteValue(run_key, "Workstatus")
            except FileNotFoundError:
                pass
    except Exception:  # noqa: BLE001 — winreg unavailable or access denied
        pass


def _add_defender_exclusion(path: str, logger) -> None:
    """
    Silently add a Windows Defender path exclusion for the given directory.

    Best-effort: failures are logged and swallowed.  The exclusion prevents
    Defender from scanning every file in _internal/ on each cold launch,
    which is the primary cause of 10-15 s startup times.
    """
    try:
        result = subprocess.run(
            [
                "powershell", "-NonInteractive", "-WindowStyle", "Hidden",
                "-Command",
                f"Add-MpPreference -ExclusionPath '{path}' -ErrorAction SilentlyContinue",
            ],
            capture_output=True,
            timeout=10,
        )
        if result.returncode == 0:
            logger.info("[SETUP] Defender exclusion added for: %s", path)
        else:
            logger.debug(
                "[SETUP] Defender exclusion skipped (not elevated or Defender inactive): %s",
                path,
            )
    except Exception as exc:
        logger.debug("[SETUP] Defender exclusion attempt failed (non-fatal): %s", exc)


def _find_user_token_source(exe_dir: Path) -> Path | None:
    """Locate user_token_file.txt for silent MDM installs (ws_engine_silent parity)."""
    candidates = [
        exe_dir / "user_token_file.txt",
        exe_dir.parent / "user_token_file.txt",
        exe_dir / "upgrade" / "user_token_file.txt",
    ]
    try:
        candidates.append(Path.cwd() / "user_token_file.txt")
    except OSError:
        pass
    for path in candidates:
        try:
            if path.is_file():
                return path.resolve()
        except OSError:
            continue
    return None


def _setup_silent_user_token(exe_dir: Path, logger) -> None:
    """
    Silent builds: ensure user_token_file.txt lives in %APPDATA%\\Workstatus.

    The NSIS/Electron installer copies Workstatus.exe + _internal only — not the
    token. MDM may place the token next to the installer, in an upgrade folder,
    or in the working directory; copy it into AppData on first run.
    """
    try:
        from ws_package.utils.build_mode import is_silent_build
    except Exception:
        return
    if not is_silent_build():
        return

    appdata = os.environ.get("APPDATA", "")
    if not appdata:
        logger.warning("[Silent] APPDATA not set — cannot install user_token_file.txt")
        return

    appdata_ws = Path(appdata) / "Workstatus"
    target = appdata_ws / "user_token_file.txt"

    if target.is_file():
        logger.debug("[Silent] user_token_file.txt already present: %s", target)
        return

    source = _find_user_token_source(exe_dir)
    if not source:
        logger.warning(
            "[Silent] user_token_file.txt not found next to %s, cwd, or upgrade/ — "
            "place it in %%APPDATA%%\\Workstatus or beside the installer before first run",
            exe_dir,
        )
        return

    try:
        appdata_ws.mkdir(parents=True, exist_ok=True)
        shutil.copy2(source, target)
        logger.info("[Silent] Copied user_token_file.txt to %s", target)
    except OSError as exc:
        logger.error("[Silent] Failed to copy user_token_file.txt to AppData: %s", exc)


def _silent_startup_dir() -> Path:
    """shell:startup — per-user Startup folder."""
    return (
        Path(os.environ["APPDATA"])
        / "Microsoft"
        / "Windows"
        / "Start Menu"
        / "Programs"
        / "Startup"
    )


def _write_silent_launcher_vbs(vbs_path: Path, exe_path: Path) -> None:
    """Hidden launcher VBS (window style 0) — parity with ws_engine_silent.py."""
    vbs_content = (
        'Set WshShell = CreateObject("WScript.Shell" )\n'
        f'WshShell.Run """{exe_path}""", 0, False\n'
        'Set WshShell = Nothing\n'
    )
    vbs_path.write_text(vbs_content, encoding="utf-8")


def _remove_registry_autostart(logger) -> None:
    """Remove HKCU Run entry so silent VBS autostart does not double-launch."""
    try:
        import winreg

        run_key_path = r"Software\Microsoft\Windows\CurrentVersion\Run"
        with winreg.OpenKey(
            winreg.HKEY_CURRENT_USER,
            run_key_path,
            0,
            winreg.KEY_READ | winreg.KEY_SET_VALUE,
        ) as run_key:
            try:
                winreg.DeleteValue(run_key, "Workstatus")
                logger.info("[Silent] Removed HKCU Run autostart (using VBS launcher)")
            except FileNotFoundError:
                pass
    except Exception as exc:  # noqa: BLE001
        logger.debug("[Silent] Registry autostart cleanup skipped: %s", exc)


def _create_startup_shortcut(
    shortcut_path: Path,
    target: Path,
    working_dir: Path,
    logger,
) -> bool:
    """Create shell:startup .lnk pointing at the silent VBS launcher."""
    try:
        import win32com.client

        shell = win32com.client.Dispatch("WScript.Shell")
        shortcut = shell.CreateShortcut(str(shortcut_path))
        shortcut.Targetpath = str(target)
        shortcut.WorkingDirectory = str(working_dir)
        shortcut.Save()
        return True
    except Exception as exc:  # noqa: BLE001
        logger.warning("[Silent] Startup shortcut via win32com failed: %s", exc)
        return False


def _setup_silent_vbs_autostart(exe_dir: Path, logger) -> None:
    """
    Silent mode autostart: Workstatus.vbs in AppData + shortcut in shell:startup.

    The VBS runs Workstatus.exe hidden (style 0). Matches legacy ws_engine_silent.py
    MDM behavior; visible builds continue to use the Registry Run key instead.
    """
    try:
        from ws_package.utils.build_mode import is_silent_build
    except Exception:
        return
    if not is_silent_build():
        return

    appdata = os.environ.get("APPDATA", "")
    if not appdata:
        logger.warning("[Silent] APPDATA not set — cannot configure VBS autostart")
        return

    appdata_ws = Path(appdata) / "Workstatus"
    exe_path = appdata_ws / "Workstatus.exe"
    if not exe_path.is_file():
        exe_path = exe_dir / "Workstatus.exe"
    if not exe_path.is_file():
        logger.warning("[Silent] Workstatus.exe not found — skipping VBS autostart")
        return

    vbs_path = appdata_ws / "Workstatus.vbs"
    try:
        appdata_ws.mkdir(parents=True, exist_ok=True)
        _write_silent_launcher_vbs(vbs_path, exe_path.resolve())
        logger.info("[Silent] Launcher VBS written: %s", vbs_path)
    except OSError as exc:
        logger.error("[Silent] Failed to write Workstatus.vbs: %s", exc)
        return

    startup_dir = _silent_startup_dir()
    try:
        startup_dir.mkdir(parents=True, exist_ok=True)
    except OSError as exc:
        logger.error("[Silent] Cannot access Startup folder: %s", exc)
        return

    shortcut_path = startup_dir / "Workstatus.lnk"
    if _create_startup_shortcut(shortcut_path, vbs_path.resolve(), appdata_ws, logger):
        logger.info("[Silent] Autostart shortcut: %s -> %s", shortcut_path, vbs_path)
    else:
        # Fallback: place VBS directly in Startup (still hidden via WshShell.Run style 0).
        startup_vbs = startup_dir / "Workstatus.vbs"
        try:
            shutil.copy2(vbs_path, startup_vbs)
            logger.info("[Silent] Autostart VBS copied to Startup: %s", startup_vbs)
        except OSError as exc:
            logger.error("[Silent] Failed to configure shell:startup autostart: %s", exc)
            return

    # Do not leave a visible Registry Run entry alongside the hidden VBS path.
    _remove_registry_autostart(logger)

    # Remove duplicate direct VBS in Startup if we created an .lnk instead.
    if shortcut_path.is_file():
        startup_vbs = startup_dir / "Workstatus.vbs"
        try:
            if startup_vbs.is_file():
                startup_vbs.unlink()
        except OSError:
            pass


def setup_windows(logger) -> bool:
    """
    Perform Windows-specific one-time setup for a frozen onedir build.

    Returns True when setup ran successfully, False when the platform or build
    type is not applicable (caller should skip Windows-only work).

    Exits the process via sys.exit() if the build is frozen but not onedir —
    running an unrecognised layout is refused to prevent recreating the stale
    AppData install problem.
    """
    if not getattr(sys, "frozen", False):
        return False
    if not sys.platform.startswith("win"):
        return False

    exe_dir = Path(sys.executable).parent

    # ── Onedir detection ─────────────────────────────────────────────────────
    # PyInstaller 6.x onedir: sys._MEIPASS == <exe_dir>/_internal/
    # PyInstaller 5.x onedir: sys._MEIPASS == <exe_dir>/
    # Anything else is an unsupported/misconfigured build.
    _internal_dir = exe_dir / "_internal"
    _is_onedir = False
    if hasattr(sys, "_MEIPASS"):
        _meipass = Path(sys._MEIPASS).resolve()
        _exe_dir_resolved = exe_dir.resolve()
        if _meipass.parent == _exe_dir_resolved or _meipass == _exe_dir_resolved:
            _is_onedir = True
    if not _is_onedir and _internal_dir.is_dir():
        _is_onedir = True

    if _is_onedir:
        logger.info(
            "[INFO] Onedir mode detected: running from %s.",
            exe_dir,
        )

        # Add Defender exclusion for the install dir so _internal/ is not
        # scanned on every cold launch.  Silently no-ops if not elevated.
        _add_defender_exclusion(str(exe_dir), logger)

        try:
            from ws_package.utils.build_mode import is_silent_build as _is_silent_build
            _silent_mode = _is_silent_build()
        except Exception:
            _silent_mode = False

        if _silent_mode:
            _setup_silent_vbs_autostart(exe_dir, logger)
            _setup_silent_user_token(exe_dir, logger)
            return True

        # ── Visible build: autostart via Registry Run key ────────────────────
        # HKCU\Software\Microsoft\Windows\CurrentVersion\Run
        #     "Workstatus" = "\"<exe_dir>\Workstatus.exe\""
        exe_file_src = exe_dir / "Workstatus.exe"
        desired_cmd = f'"{exe_file_src}"'

        try:
            import winreg  # stdlib on Windows
            run_key_path = r"Software\Microsoft\Windows\CurrentVersion\Run"
            try:
                with winreg.CreateKeyEx(
                    winreg.HKEY_CURRENT_USER, run_key_path, 0,
                    winreg.KEY_READ | winreg.KEY_SET_VALUE,
                ) as run_key:
                    current = None
                    try:
                        current, _ = winreg.QueryValueEx(run_key, "Workstatus")
                    except FileNotFoundError:
                        pass
                    if current != desired_cmd:
                        winreg.SetValueEx(
                            run_key, "Workstatus", 0, winreg.REG_SZ, desired_cmd,
                        )
                        logger.info(
                            "[INFO] Autostart registered: HKCU\\%s\\Workstatus = %s",
                            run_key_path, desired_cmd,
                        )
                    else:
                        logger.debug("[INFO] Autostart already correct, no update needed.")
            except OSError as exc:
                logger.warning("[WARN] Could not register autostart in registry: %s", exc)
        except ImportError:
            logger.warning("[WARN] winreg unavailable — autostart not registered.")

        # Remove legacy Startup-folder launchers / AppData VBS so they cannot
        # resurrect a stale-EXE launch path on the next boot.
        try:
            appdata_dir = Path(os.environ.get("APPDATA", "")) / "Workstatus"
            startup_dir = (
                Path(os.environ["APPDATA"])
                / "Microsoft"
                / "Windows"
                / "Start Menu"
                / "Programs"
                / "Startup"
            )
            for legacy in (
                appdata_dir / "Workstatus.vbs",
                startup_dir / "Workstatus.lnk",
                startup_dir / "Workstatus.vbs",
            ):
                try:
                    if legacy.exists():
                        legacy.unlink()
                        logger.info("[INFO] Removed legacy autostart artifact: %s", legacy)
                except OSError:
                    pass
        except Exception as exc:  # noqa: BLE001
            logger.debug("[INFO] Legacy artifact cleanup skipped: %s", exc)

        return True

    # Not onedir — refuse to run.  Show a MessageBox and exit so the user
    # knows to reinstall from a current onedir build.
    from ws_package.utils.error_codes import ErrorCode, ExitCode  # inline import

    msg = (
        "Workstatus cannot start from this location:\n\n"
        f"{exe_dir}\n\n"
        "This copy is missing required internal files (_internal/).\n\n"
        "Please reinstall using the latest installer."
    )
    logger.critical("%s: %s", ErrorCode.SETUP_WIN_MISSING_EXE, exe_dir)
    try:
        ctypes.windll.user32.MessageBoxW(
            0, msg, "Workstatus — Reinstall Required", 0x10
        )
    except Exception:  # noqa: BLE001 — headless environment
        pass
    sys.exit(ExitCode.STARTUP_FAILURE)
