#!/usr/bin/env python3
"""Entry point: put src/ on the path and hand off to the real launcher."""
import os
import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parent
sys.path.insert(0, str(ROOT / "src"))

# Console encoding is handled by clipshelf/__init__.py so that EVERY entry
# point gets it, not just this one — but the app is imported below, after
# the update step, and a staged-update log line could be printed before
# then. So do it here too; both are idempotent.
if os.name == "nt":
    try:
        import ctypes
        ctypes.windll.kernel32.SetConsoleOutputCP(65001)
    except Exception:
        pass
for _stream in (sys.stdout, sys.stderr):
    try:
        _stream.reconfigure(encoding="utf-8", errors="replace")
    except Exception:
        pass                      # None under pythonw; handled just below
os.environ.setdefault("PYTHONIOENCODING", "utf-8")   # and for any child

# Windowed launch uses pythonw.exe, which sets sys.stdout/sys.stderr to
# None — the first print() then dies with AttributeError and the app
# vanishes with no window and no message. Redirect to a log file BEFORE
# importing anything that might print.
if sys.stdout is None or sys.stderr is None:
    try:
        _log = open(ROOT / "app.log", "a", buffering=1, encoding="utf-8",
                    errors="replace")
        sys.stdout = sys.stderr = _log
        import time as _t
        _log.write(f"\n===== started {_t.strftime('%Y-%m-%d %H:%M:%S')} =====\n")
    except Exception:
        import io
        sys.stdout = sys.stderr = io.StringIO()   # never let logging kill the app

# A staged update is swapped in HERE — before the app is imported, so no
# module is loaded and no file is locked.
try:
    from clipshelf.updater import apply_pending
    apply_pending()
except Exception as _e:                     # an update must never brick startup
    print(f"[update] skipped ({_e})")

def _install_new_deps():
    """An update that changed requirements.txt leaves a marker. Act on it
    BEFORE importing the app — the whole point is that a module it needs
    may not be installed yet.

    Only for an installed copy: the zip gets the same job done by run.bat
    refreshing its .venv."""
    marker = ROOT / "deps-stale"
    if not marker.exists() or not (ROOT / "installed").exists():
        return
    import subprocess
    print("[update] installing new dependencies...", flush=True)
    r = subprocess.run([sys.executable, "-m", "pip", "install",
                        "--no-warn-script-location", "-r", str(ROOT / "requirements.txt")],
                       capture_output=True, text=True)
    if r.returncode == 0:
        marker.unlink(missing_ok=True)
        print("[update] dependencies up to date", flush=True)
    else:
        # left in place so the next start tries again rather than limping
        print("[update] dependency install failed:\n"
              + (r.stderr or "")[-1500:], flush=True)


try:
    _install_new_deps()
except Exception as _e:
    print(f"[update] dependency step skipped ({_e})")

from clipshelf.launch import main  # noqa: E402

if __name__ == "__main__":
    main()
