"""
Linux 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 stat
from pathlib import Path


_TOKEN_FILE = "user_token_file.txt"
# ---------------------------------------------------------------------------
# Setup script template
# ---------------------------------------------------------------------------

_SETUP_SH_BODY = """\
#!/bin/bash

REQUIRED_VERSION="3.10.0"
INSTALL_VERSION="3.10.12"
PYTHON_CMD=""
PYTHON_VERSION=""
INSTALL_NEEDED=false

version_lt() {
    IFS='.' read -r -a ver1 <<< "$1"
    IFS='.' read -r -a ver2 <<< "$2"
    for i in 0 1 2; do
        v1=${ver1[i]:-0}
        v2=${ver2[i]:-0}
        if ((v1 < v2)); then
            return 0
        elif ((v1 > v2)); then
            return 1
        fi
    done
    return 1
}

CLIENT_DIR=$(pwd)
VENV_DIR="$CLIENT_DIR/venv"
TARGET_DIR="$HOME/Workstatus"
WORKSTATUS_EXEC="Workstatus"

echo "[INFO] Detecting suitable Python 3.10.x"

if command -v python3.10 &>/dev/null; then
    PYTHON_CMD="python3.10"
    PYTHON_VERSION="$("$PYTHON_CMD" --version 2>&1 | awk '{print $2}')"
    echo "[INFO] Detected Python: $PYTHON_CMD, version: $PYTHON_VERSION"
    if version_lt "$PYTHON_VERSION" "$REQUIRED_VERSION"; then
        echo "[INFO] Existing Python 3.10.x ($PYTHON_VERSION) is older than $REQUIRED_VERSION. Will try installing $INSTALL_VERSION."
        INSTALL_NEEDED=true
    else
        echo "[INFO] Suitable Python version already present: $PYTHON_VERSION"
    fi
else
    echo "[INFO] No Python 3.10.x found. Will attempt to install Python $INSTALL_VERSION."
    INSTALL_NEEDED=true
fi

if [ "$INSTALL_NEEDED" = "true" ]; then
    if sudo -n true 2>/dev/null; then
        echo "[INFO] Installing Python $INSTALL_VERSION..."
        sudo apt update -y || echo "[WARN] Failed to update apt."
        sudo apt install -y software-properties-common || echo "[WARN] Failed to install software-properties-common."
        sudo add-apt-repository -y ppa:deadsnakes/ppa || echo "[WARN] Failed to add deadsnakes PPA."
        sudo apt update -y || echo "[WARN] Failed to update after PPA."
        sudo apt install -y python3.10 python3.10-venv python3.10-dev || echo "[ERROR] Failed to install Python 3.10."
        PYTHON_CMD="python3.10"
    else
        echo "[WARN] No sudo rights. Cannot install Python $INSTALL_VERSION. Will continue with detected Python (if any)."
    fi
fi

echo "[INFO] Installing additional system dependencies..."
if sudo -n true 2>/dev/null; then
    sudo apt install -y scrot xdotool x11-utils || echo "[WARN] Failed to install some system dependencies."
else
    echo "[WARN] Skipping dependency installation (no sudo rights)."
fi

echo "[INFO] Checking for $PYTHON_CMD venv support..."
if ! "$PYTHON_CMD" -m venv --help &>/dev/null; then
    echo "[INFO] venv not supported, installing..."
    if sudo -n true 2>/dev/null; then
        sudo apt update -y || echo "[WARN] Failed to update apt before venv install."
        sudo apt install -y python3-venv || echo "[WARN] Failed to install python3-venv."
    else
        echo "[WARN] Cannot install python3-venv (no sudo). Will try pip/virtualenv fallback."
    fi
fi

echo "[INFO] Setting up Python virtual environment..."

if [ -d "$VENV_DIR" ]; then
    echo "[INFO] Virtual environment already exists: $VENV_DIR"
else
    VENV_CREATED=false

    if "$PYTHON_CMD" -m venv "$VENV_DIR" &>/dev/null; then
        echo "[INFO] Virtual environment created successfully using '$PYTHON_CMD -m venv'."
        VENV_CREATED=true
    else
        echo "[INFO] Failed to create venv using '$PYTHON_CMD -m venv'."

        if sudo -n true 2>/dev/null; then
            echo "[INFO] Attempting to install 'python3-venv' via apt..."
            sudo apt update -y || echo "[WARN] Failed to update apt before venv install."
            sudo apt install -y python3-venv || echo "[WARN] Failed to install python3-venv."
        else
            echo "[WARN] Skipping python3-venv installation (no sudo)."
        fi

        if "$PYTHON_CMD" -m venv "$VENV_DIR" &>/dev/null; then
            echo "[INFO] Virtual environment created successfully after installing 'python3-venv'."
            VENV_CREATED=true
        else
            echo "[INFO] Attempting fallback with pip/virtualenv..."
        fi
    fi

    if [ "$VENV_CREATED" = "false" ]; then
        echo "[INFO] Trying to create virtual environment using pip + virtualenv..."
        if sudo -n true 2>/dev/null; then
            sudo apt update -y || echo "[WARN] Failed to update apt before pip install."
            sudo apt install -y python3-pip || echo "[WARN] Failed to install python3-pip."
        else
            echo "[WARN] Skipping python3-pip installation (no sudo)."
        fi

        "$PYTHON_CMD" -m pip install virtualenv || { echo "[ERROR] Failed to install 'virtualenv' via pip. Exiting."; exit 1; }

        virtualenv "$VENV_DIR"
        if [ $? -eq 0 ]; then
            echo "[INFO] Virtual environment created successfully using 'virtualenv'."
            VENV_CREATED=true
        else
            echo "[ERROR] Failed to create virtual environment using 'virtualenv'. Exiting."
            exit 1
        fi
    fi
fi

if [ ! -d "$VENV_DIR" ]; then
    echo "[CRITICAL ERROR] Virtual environment was not created. Application cannot run. Exiting."
    exit 1
fi

source "$VENV_DIR/bin/activate"
pip install --upgrade pip || echo "[WARN] pip upgrade failed."
pip install mss pygetwindow pyautogui || echo "[WARN] Some pip packages failed to install."
deactivate

FILE="$TARGET_DIR/process.txt"
[ ! -f "$FILE" ] && touch "$FILE"

echo "[INFO] Setup complete (venv ready). Start the Workstatus desktop app and log in to launch the agent."
"""

_SETUP_SH_SILENT_AUTOSTART = """\

# Silent MDM autostart — launch Workstatus on user login
PROFILE_FILE="$HOME/.profile"
LOG_FILE="$TARGET_DIR/mylogs.log"
START_CMD="nohup bash -c 'source \\"$VENV_DIR/bin/activate\\" && \\"$TARGET_DIR/$WORKSTATUS_EXEC\\"' > \\"$LOG_FILE\\" 2>&1 &"

if ! grep -Fq "Workstatus/Workstatus" "$PROFILE_FILE" 2>/dev/null; then
    echo "$START_CMD" >> "$PROFILE_FILE"
    echo "[INFO] Silent autostart entry added to $PROFILE_FILE."
else
    echo "[INFO] Silent autostart already configured in $PROFILE_FILE."
fi

echo "[INFO] Setup complete (silent). Workstatus will start on login."

nohup bash -c 'source "$VENV_DIR/bin/activate" && "$TARGET_DIR/$WORKSTATUS_EXEC"' > "$LOG_FILE" 2>&1 & disown
"""


# ---------------------------------------------------------------------------
# Public entry point
# ---------------------------------------------------------------------------

def setup_linux(logger) -> bool:
    """Set up and launch the Workstatus binary on Linux (frozen builds only).

    Steps performed when not yet running from the installation directory:
      1. Validate that the source executable exists.
      2. Copy the binary into ~/Workstatus/.
      3. Write setup.sh (Python venv bootstrap) next to the binary in exe_dir.
      4. Re-launch from the installation directory and exit the current process.

    When already running from ~/Workstatus:
      1. If setup.sh or venv is missing, write setup.sh (if needed) and return False.
      2. When venv is ready, return True so Electron can spawn the agent after login.

    Visible builds must not autostart from ~/.profile — Electron starts Python after
    login.  Silent (MDM) builds register ~/.profile autostart via setup.sh and at
    runtime when venv is ready.

    Returns:
        True  — caller should proceed with normal startup (Electron-spawned process).
        False — install/setup only; do not run main() (no IPC/monitoring).
    """
    if not (getattr(sys, "frozen", False) and sys.platform == "linux"):
        return False

    # Import inline to avoid circular imports at module level.
    from ws_package.utils.build_mode import is_silent_build
    from ws_package.utils.error_codes import ErrorCode, ExitCode
    from ws_package.utils.update_linux import ensure_linux_deb_upgrade_script_in_install_dir

    silent = is_silent_build()
    exe_dir = Path(sys.executable).parent
    exe_file_src = exe_dir / "Workstatus"

    target_dir = Path.home() / "Workstatus"
    workstatus_exec_target = target_dir / "Workstatus"

    already_in_target = exe_dir.resolve() == target_dir.resolve()

    # ------------------------------------------------------------------
    # Case A: not yet running from target_dir — copy, write setup.sh,
    #         relaunch, and exit.
    # ------------------------------------------------------------------
    if not already_in_target:
        logger.info("[INFO] Linux setup: copying files to %s", target_dir)

        if not exe_file_src.exists():
            logger.critical("%s: %s", ErrorCode.SETUP_LIN_MISSING_EXE, exe_file_src)
            sys.exit(ExitCode.STARTUP_FAILURE)

        token_target = target_dir / _TOKEN_FILE
        token_file_src = None
        if silent:
            token_file_src = _find_token_file_src(exe_dir)
            if not token_target.exists() and token_file_src is None:
                logger.critical(
                    "%s: place %s next to %s before first run.",
                    ErrorCode.SETUP_LIN_MISSING_TOKEN,
                    _TOKEN_FILE,
                    exe_file_src,
                )
                sys.exit(ExitCode.STARTUP_FAILURE)

        try:
            target_dir.mkdir(parents=True, exist_ok=True)
            if not workstatus_exec_target.exists():
                shutil.copy2(exe_file_src, target_dir)
                workstatus_exec_target.chmod(
                    workstatus_exec_target.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
                )
                logger.info("[INFO] Copied executable to %s", target_dir)
            if silent and not token_target.exists() and token_file_src is not None:
                _copy_token_file_to(target_dir, token_file_src, logger)
        except Exception as exc:
            logger.critical("%s: %s", ErrorCode.SETUP_LIN_COPY_FAILED, exc)
            sys.exit(ExitCode.STARTUP_FAILURE)

        _write_setup_sh(target_dir, logger, silent=silent)
        ensure_linux_deb_upgrade_script_in_install_dir(target_dir)
        if silent:
            logger.info(
                "[INFO] Binary and token installed at %s — run setup.sh to enable silent autostart.",
                target_dir,
            )
        else:
            logger.info(
                "[INFO] Binary installed at %s — run setup.sh, then start the desktop app and log in.",
                target_dir,
            )
        logger.critical("%s", ErrorCode.SETUP_LIN_HANDOFF)
        sys.exit(ExitCode.OK)

    # ------------------------------------------------------------------
    # Case B: already in ~/Workstatus — gate main() until setup.sh has run.
    # ------------------------------------------------------------------
    logger.info("[INFO] Workstatus already running from target directory. Skipping copy.")

    if silent:
        _require_token_file(target_dir, logger)

    setup_file = target_dir / "setup.sh"
    if not setup_file.exists():
        _write_setup_sh(target_dir, logger, silent=silent)
        logger.info(
            "[INFO] setup.sh created at %s — exiting; run it before normal startup.",
            setup_file,
        )
        return False

    if not _linux_setup_complete(target_dir):
        logger.info(
            "[INFO] Linux venv not ready under %s — exiting (run setup.sh first).",
            target_dir,
        )
        return False

    if silent:
        try:
            existing_setup = setup_file.read_text(encoding="utf-8")
        except OSError:
            existing_setup = ""
        if not _setup_sh_has_silent_autostart(existing_setup):
            _write_setup_sh(target_dir, logger, silent=True)

    ensure_linux_deb_upgrade_script_in_install_dir(target_dir)
    if silent:
        _ensure_silent_profile_autostart(target_dir, logger)
    else:
        _remove_legacy_profile_autostart(logger)
    return True


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

def _linux_setup_complete(target_dir: Path) -> bool:
    """True when setup.sh has created the per-install venv."""
    return (target_dir / "venv" / "bin" / "activate").is_file()


def _find_token_file_src(exe_dir: Path) -> Path | None:
    """Locate user_token_file.txt next to the binary or common deploy locations."""
    candidates = (
        exe_dir / _TOKEN_FILE,
        Path.cwd() / _TOKEN_FILE,
        Path.home() / "Downloads" / _TOKEN_FILE,
        Path.home() / "Desktop" / _TOKEN_FILE,
    )
    for candidate in candidates:
        if candidate.is_file():
            return candidate.resolve()
    return None


def _copy_token_file_to(target_dir: Path, token_src: Path, logger) -> None:
    token_target = target_dir / _TOKEN_FILE
    shutil.copy2(token_src, token_target)
    token_target.chmod(stat.S_IRUSR | stat.S_IWUSR)
    logger.info("[INFO] Copied token file to %s", token_target)


def _require_token_file(target_dir: Path, logger) -> None:
    """Exit when silent install is missing user_token_file.txt in ~/Workstatus."""
    from ws_package.utils.error_codes import ErrorCode, ExitCode

    token_target = target_dir / _TOKEN_FILE
    if token_target.is_file():
        return
    logger.critical(
        "%s: %s — place %s in %s alongside the Workstatus binary.",
        ErrorCode.SETUP_LIN_MISSING_TOKEN,
        token_target,
        _TOKEN_FILE,
        target_dir,
    )
    sys.exit(ExitCode.STARTUP_FAILURE)


def _write_setup_sh(exe_dir: Path, logger, *, silent: bool = False) -> None:
    """Write setup.sh into *exe_dir* if it does not already exist.

    Visible: venv bootstrap only (Electron starts the agent after login).
    Silent: same bootstrap plus ~/.profile autostart and immediate background launch.
    """
    setup_file = exe_dir / "setup.sh"
    if setup_file.exists():
        try:
            existing = setup_file.read_text(encoding="utf-8")
        except OSError:
            existing = ""
        has_silent_autostart = _setup_sh_has_silent_autostart(existing)
        legacy_launch = "nohup bash" in existing and "Workstatus" in existing
        if silent:
            if has_silent_autostart:
                logger.info("[INFO] setup.sh already present at %s — skipping write.", setup_file)
                return
            logger.info("[INFO] Refreshing setup.sh at %s (adding silent autostart).", setup_file)
        else:
            if not legacy_launch:
                logger.info("[INFO] setup.sh already present at %s — skipping write.", setup_file)
                return
            logger.info("[INFO] Refreshing legacy setup.sh at %s (removing agent autostart).", setup_file)

    logger.info("[INFO] Creating setup.sh at %s", setup_file)
    content = _SETUP_SH_BODY
    if silent:
        content += _SETUP_SH_SILENT_AUTOSTART
    setup_file.write_text(content, encoding="utf-8")
    setup_file.chmod(setup_file.stat().st_mode | stat.S_IXUSR | stat.S_IXOTH)
    logger.info("[INFO] setup.sh written and marked executable.")


def _setup_sh_has_silent_autostart(content: str) -> bool:
    return "Silent MDM autostart" in content


def _silent_profile_autostart_line(target_dir: Path) -> str:
    venv_activate = target_dir / "venv" / "bin" / "activate"
    workstatus_exec = target_dir / "Workstatus"
    log_file = target_dir / "mylogs.log"
    return (
        f"nohup bash -c 'source \"{venv_activate}\" && \"{workstatus_exec}\"' "
        f"> \"{log_file}\" 2>&1 &"
    )


def _ensure_silent_profile_autostart(target_dir: Path, logger) -> None:
    """Ensure ~/.profile launches Workstatus on login (silent MDM only)."""
    profile_path = Path.home() / ".profile"
    start_line = _silent_profile_autostart_line(target_dir)

    try:
        if profile_path.exists():
            text = profile_path.read_text(encoding="utf-8", errors="replace")
            if "Workstatus/Workstatus" in text and "nohup" in text:
                logger.info("[INFO] Silent autostart already present in %s.", profile_path)
                return
        else:
            text = ""

        if text and not text.endswith("\n"):
            text += "\n"
        text += start_line + "\n"
        profile_path.write_text(text, encoding="utf-8")
        logger.info("[INFO] Added silent Workstatus autostart to %s.", profile_path)
    except OSError as exc:
        logger.warning("[WARN] Could not configure silent autostart in %s: %s", profile_path, exc)


def _remove_legacy_profile_autostart(logger) -> None:
    """Remove old ~/.profile lines that launched Workstatus before Electron login."""
    profile_path = Path.home() / ".profile"
    if not profile_path.exists():
        return

    markers = (
        "Workstatus/venv",
        "Workstatus/Workstatus",
        "/Workstatus/Workstatus",
        "TARGET_DIR/$WORKSTATUS_EXEC",
    )
    try:
        text = profile_path.read_text(encoding="utf-8", errors="replace")
    except OSError as exc:
        logger.warning("[WARN] Could not read %s: %s", profile_path, exc)
        return

    kept_lines = []
    removed = 0
    for line in text.splitlines(keepends=True):
        stripped = line.strip()
        if stripped.startswith("nohup ") and any(m in line for m in markers):
            removed += 1
            continue
        kept_lines.append(line)

    if removed == 0:
        return

    try:
        profile_path.write_text("".join(kept_lines), encoding="utf-8")
        logger.info("[INFO] Removed %d legacy Workstatus autostart line(s) from %s.", removed, profile_path)
    except OSError as exc:
        logger.warning("[WARN] Could not update %s: %s", profile_path, exc)
