#!/usr/bin/env python3
"""web.py — Starts the Brimoza web panel (FastAPI/uvicorn).

This launcher adds the repo root to sys.path and serves the ``webapp.server:app``
application via uvicorn. The panel is for monitoring bot status, starting and
stopping dry_run/testnet/live, and viewing logs and scans.

Example usage:
    python scripts/web.py                    # http://127.0.0.1:8787 (this machine only)
    python scripts/web.py --reload           # automatic reload for development

SECURITY:
  - The panel NEVER exposes api_key/api_secret; starting LIVE requires both the
    request confirmation (confirm_live='LIVE') and the config.py environment-variable gate.
  - The panel can start LIVE real-money trading and the API has NO AUTHENTICATION.
    For this reason, by DEFAULT it listens only on loopback (127.0.0.1).
  - The RECOMMENDED way for REMOTE access: keep the server on 127.0.0.1 and use an SSH tunnel:
        ssh -L 8787:127.0.0.1:8787 user@server
  - Exposing it to the network anyway (a non-loopback --host) MANDATORILY requires the
    --allow-remote flag AND the BRIMOZA_PANEL_TOKEN environment variable (Bearer token).
"""
from __future__ import annotations

import argparse
import ipaddress
import os
import pathlib
import sys

# Add the repo root to sys.path so the "webapp" and "coinbot" packages can be imported.
_REPO_ROOT = pathlib.Path(__file__).resolve().parent.parent
sys.path.insert(0, str(_REPO_ROOT))

PANEL_TOKEN_ENV = "BRIMOZA_PANEL_TOKEN"


def _is_loopback(host: str) -> bool:
    """Is host loopback (this machine only)? 'localhost' and 127.x / ::1 -> True."""
    h = (host or "").strip().lower()
    if h == "localhost":
        return True
    try:
        return ipaddress.ip_address(h).is_loopback
    except ValueError:
        return False  # unresolvable hostname -> be cautious: treat as not loopback


def _parse_args(argv: list[str] | None = None) -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        prog="web.py",
        description="Brimoza web panelini (FastAPI/uvicorn) baslatir.",
    )
    parser.add_argument("--host", default="127.0.0.1",
                        help="Dinlenecek arayuz adresi (varsayilan: 127.0.0.1 = yalnizca bu makine).")
    parser.add_argument("--port", type=int, default=8787, help="Dinlenecek port (varsayilan: 8787).")
    parser.add_argument("--reload", action="store_true",
                        help="Kod degisince sunucuyu otomatik yeniden yukle (gelistirme modu).")
    parser.add_argument("--allow-remote", action="store_true",
                        help="Loopback DISI bir --host'a baglanmaya izin ver (token ZORUNLU; risklidir).")
    return parser.parse_args(argv)


def main(argv: list[str] | None = None) -> int:
    args = _parse_args(argv)

    # Load .env explicitly (so auth + keys enter os.environ) so that the auth_enforced()
    # check below and the uvicorn subprocess see the correct values.
    try:
        from dotenv import load_dotenv
        load_dotenv(_REPO_ROOT / ".env")
    except Exception:  # noqa: BLE001
        pass

    # Network-exposure guard: the panel includes LIVE trade control and the API has no auth.
    if not _is_loopback(args.host):
        if not args.allow_remote:
            print(
                f"HATA: '{args.host}' loopback degil. Panel LIVE islem kontrolu icerir; "
                f"ag'a acmak risklidir.\n"
                f"  Guvenli uzaktan erisim icin SSH tunnel kullanin (sunucu 127.0.0.1'de kalsin):\n"
                f"    ssh -L {args.port}:127.0.0.1:{args.port} kullanici@sunucu\n"
                f"  Yine de ag'a acmak istiyorsaniz: --allow-remote ekleyin VE {PANEL_TOKEN_ENV} ayarlayin."
            )
            return 2
        import webapp.auth as _auth
        if not _auth.auth_enforced():
            print(
                "HATA: --allow-remote icin KIMLIK DOGRULAMA zorunlu. Sunlardan en az birini ayarlayin:\n"
                "  - BRIMOZA_PANEL_PASSWORD (web login; ornek: export BRIMOZA_PANEL_PASSWORD='guclu-parola')\n"
                "  - BRIMOZA_PANEL_TOKEN   (API Bearer token; ornek: export BRIMOZA_PANEL_TOKEN=$(openssl rand -hex 24))\n"
                "  Ayrica paneli MUTLAKA TLS (https) ters-vekil arkasinda yayinlayin."
            )
            return 2
        print(
            f"!!! UYARI: panel AG'A aciliyor ({args.host}:{args.port}) (--allow-remote). "
            f"Token zorunlu; yine de guvenilmeyen aglarda calistirmayin. !!!"
        )

    # On loopback (local) startup: grant explicit insecure permission so the app passes
    # its fail-closed startup check even when auth is disabled. It is NEVER granted when
    # exposing to the network (NON-loopback) -> there auth is already mandatory (the check above).
    if _is_loopback(args.host):
        os.environ.setdefault("BRIMOZA_PANEL_ALLOW_INSECURE", "1")

    import uvicorn

    print(f"Brimoza paneli baslatiliyor — panel adresi http://{args.host}:{args.port}")
    # proxy_headers + forwarded_allow_ips: behind a TLS reverse proxy, TRUST X-Forwarded-Proto
    # only from the loopback proxy (so the cookie 'secure' flag is computed correctly).
    uvicorn.run(
        "webapp.server:app",
        host=args.host, port=args.port, reload=args.reload,
        proxy_headers=True, forwarded_allow_ips="127.0.0.1",
    )
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
