"""
Native desktop launcher — starts the biosync server and opens it in an OS window.

`python -m biosync.app` (or the frozen .app/.exe) runs this. It uses pywebview for
a real native window; if pywebview isn't available it falls back to opening the
default browser, so the app always launches.
"""

from __future__ import annotations

import os
import threading
import time

from .server import create_app

DEFAULT_PORT = 8765


def _find_free_port(preferred=DEFAULT_PORT) -> int:
    import socket
    for port in (preferred, 0):
        try:
            s = socket.socket(); s.bind(("127.0.0.1", port))
            p = s.getsockname()[1]; s.close()
            return p
        except OSError:
            continue
    return preferred


def _serve(app, port):
    # threaded Flask dev server is fine for a single local desktop user
    app.run(host="127.0.0.1", port=port, threaded=True, use_reloader=False)


def main(data_dir: str | None = None):
    data_dir = data_dir or os.environ.get("BIOSYNC_DATA",
                                           os.path.expanduser("~/biosync-sessions"))
    port = _find_free_port()
    app = create_app(data_dir)
    threading.Thread(target=_serve, args=(app, port), daemon=True).start()
    url = f"http://127.0.0.1:{port}/"

    # wait for the server to accept connections
    _wait_until_up(port)

    try:
        import webview  # pywebview
        webview.create_window("biosync", url, width=1100, height=820)
        webview.start()
    except Exception:
        import webbrowser
        print(f"biosync running at {url}  (Ctrl+C to quit)")
        webbrowser.open(url)
        try:
            while True:
                time.sleep(1)
        except KeyboardInterrupt:
            pass


def _wait_until_up(port, timeout=10.0):
    import socket
    t0 = time.time()
    while time.time() - t0 < timeout:
        try:
            s = socket.create_connection(("127.0.0.1", port), timeout=0.3)
            s.close()
            return
        except OSError:
            time.sleep(0.1)


if __name__ == "__main__":
    main()
