"""Public (unauthenticated) endpoints for guests."""
from fastapi import APIRouter, Depends, Request
import httpx

from core.auth import get_current_user
from routes.admin_users import _get_settings_doc
from routes.auth import get_db

router = APIRouter(prefix="/api/public", tags=["public"])


@router.get("/shared-xtream")
async def shared_xtream():
    """Legacy single-Xtream shared creds endpoint.

    NOTE: still public. Kept for backward compat. For multi-profile
    selection, authenticated users should use /api/shared-profiles
    instead.
    """
    db = get_db()
    settings = await _get_settings_doc(db)
    return {
        "server": settings.get("shared_xtream_server", ""),
        "username": settings.get("shared_xtream_username", ""),
        "password": settings.get("shared_xtream_password", ""),
        "configured": bool(
            settings.get("shared_xtream_server")
            and settings.get("shared_xtream_username")
            and settings.get("shared_xtream_password")
        ),
    }


@router.get("/playback-mode")
async def playback_mode():
    """Public read-only view of admin's playback preference.

    Returns { "external_player_enabled": bool }. When True the mobile app
    launches videos in an external player (VLC / MX Player / Brouken).
    When False (default) the in-app ExoPlayer is used.
    """
    db = get_db()
    settings = await _get_settings_doc(db)
    return {
        "external_player_enabled": bool(
            settings.get("external_player_enabled", False)
        ),
        "player_notice_enabled": bool(
            settings.get("player_notice_enabled", False)
        ),
        "inline_preview_enabled": bool(
            settings.get("inline_preview_enabled", True)
        ),
    }


@router.get("/app-info")
async def app_info():
    """Public read-only payload powering:
        • In-app update popup (latest + min-supported version, download URLs, changelog)
        • About / Help section (creator info, support email, privacy policy)
        • WhatsApp contact (number + prefilled message)

    No auth required — guests see this too. Admin edits these via PUT /api/admin/settings.
    """
    db = get_db()
    s = await _get_settings_doc(db)
    return {
        "update": {
            "enabled": bool(s.get("update_enabled", False)),
            "latest_version": (s.get("app_version") or "").strip() or "1.3.0",
            "min_supported_version": (s.get("min_supported_version") or "").strip() or "1.3.0",
            "apk_url": s.get("update_apk_url") or "",
            "play_url": s.get("update_play_url") or "",
            "changelog": s.get("update_changelog") or "",
            "popup_delay_seconds": int(s.get("popup_delay_seconds") or 10),
        },
        "creator": {
            "name": s.get("creator_name") or "",
            "role": s.get("creator_role") or "",
            "avatar_url": s.get("creator_avatar_url") or "",
            "bio": s.get("creator_bio") or "",
        },
        "support": {
            "whatsapp_number": s.get("whatsapp_number") or "",
            "whatsapp_message": s.get("whatsapp_message") or "",
            "email": s.get("support_email") or "",
        },
        "flags": {
            # Mirrored from /api/public/playback-mode for resilience — even
            # if a deployment somewhere is missing the playback-mode route,
            # the device still picks up the admin choice from app-info.
            "player_notice_enabled": bool(s.get("player_notice_enabled", False)),
            "external_player_enabled": bool(s.get("external_player_enabled", False)),
            "inline_preview_enabled": bool(s.get("inline_preview_enabled", True)),
            # Push notifications kill-switch. Default FALSE — devices will
            # ONLY attempt FCM registration when admin has explicitly opted
            # in. Critical for v2.1: APKs built before google-services.json
            # was bundled WILL crash inside Firebase init if this is on.
            "push_enabled": bool(s.get("push_enabled", False)),
        },
        "privacy_policy_text": s.get("privacy_policy_text") or "",
        # FEATURE (2026-01) — Terms & Conditions admin-editable text,
        # surfaced by the About menu modal on the Account page.
        "terms_policy_text": s.get("terms_policy_text") or "",
        # FEATURE (2026-01) — Smart-TV custom "House Ad" banner. AdMob
        # is mobile-only, so Tizen / webOS pick up this admin-configured
        # snippet / image-pair instead. Only rendered when isSmartTV()
        # AND enabled is true.
        "tv_banner": {
            "enabled": bool(s.get("tv_banner_enabled", False)),
            "type": s.get("tv_banner_type") or "image",
            "html": s.get("tv_banner_html") or "",
            "image_url": s.get("tv_banner_image_url") or "",
            "click_url": s.get("tv_banner_click_url") or "",
        },
    }


@router.get("/ad-config")
async def ad_config():
    """Public AdMob configuration. The mobile app fetches this on launch
    to know whether to initialise ads, which Ad Unit IDs to use, and how
    often to trigger interstitials. When testing_mode is on, we hand out
    Google's universal TEST Ad Unit IDs to guarantee real account never
    gets charged, even if admin made a mistake in the dashboard.
    """
    db = get_db()
    s = await _get_settings_doc(db)
    testing = bool(s.get("ads_testing_mode", True))
    banner = s.get("ads_banner_id") or ""
    inter = s.get("ads_interstitial_id") or ""
    native = s.get("ads_native_id") or ""
    rewarded = s.get("ads_rewarded_id") or ""
    if testing:
        # Google's universal TEST adaptive banner unit. The previous
        # `6300978111` test unit returns a fixed 320x50 creative which
        # does NOT respect the ADAPTIVE_BANNER size hint, so it shows up
        # as a small ad with white gutters on phones. `9214589741` is
        # the Adaptive Banner test unit and stretches to fill the
        # AdView's measured width.
        banner = "ca-app-pub-3940256099942544/9214589741"
        inter = "ca-app-pub-3940256099942544/1033173712"
        # Google's universal TEST Native Advanced unit. Ensures no real
        # AdMob impressions while `testing` is on.
        native = "ca-app-pub-3940256099942544/2247696110"
        # Google's universal TEST Rewarded unit.
        rewarded = "ca-app-pub-3940256099942544/5224354917"
    return {
        "enabled": bool(s.get("ads_enabled", False)),
        # BUG-2 FIX (2026-05): expose the Users-vs-Guests sub-toggles
        # so the frontend's useAdsPolicy hook can gate ad rendering
        # per auth status. Backward-compatible defaults: guests on
        # whenever master ads_enabled is on; users off (current
        # behaviour). The admin overrides either flag from the dashboard.
        "ads_enabled_for_users": bool(s.get("ads_enabled_for_users", False)),
        "ads_enabled_for_guests": bool(
            s.get("ads_enabled_for_guests", bool(s.get("ads_enabled", False)))
        ),
        "testing": testing,
        "app_id": s.get("ads_app_id") or "",
        "banner_id": banner,
        "interstitial_id": inter,
        "native_id": native,
        "rewarded_id": rewarded,
        "interstitial_every": max(0, int(s.get("ads_interstitial_every") or 5)),
    }


# Authenticated endpoint for multi-profile picker. Guests get 401.
auth_router = APIRouter(prefix="/api", tags=["shared"])


@router.get("/geo")
async def geo(request: Request):
    """Server-side IP geolocation proxy.

    Calls ip-api.com (HTTP, free tier) from the backend so that browsers
    don't run into CORS / mixed-content blocks when serving over HTTPS.
    Falls back to ipwho.is if ip-api.com fails. Returns a minimal shape
    suitable for the InfoBar UI:
        { "city": "...", "country": "...", "country_code": "..." }
    """
    # Respect X-Forwarded-For so Kubernetes ingress / proxy chains route
    # the lookup to the real client IP rather than the cluster gateway.
    fwd = request.headers.get("x-forwarded-for", "")
    client_ip = (fwd.split(",")[0] if fwd else (request.client.host if request.client else "")).strip()
    timeout = httpx.Timeout(4.0)

    # Primary: ip-api.com
    try:
        url = "http://ip-api.com/json/"
        if client_ip:
            url += client_ip
        url += "?fields=status,country,countryCode,city,lat,lon"
        async with httpx.AsyncClient(timeout=timeout) as c:
            r = await c.get(url)
            j = r.json()
            if j.get("status") == "success":
                return {
                    "city": j.get("city") or "",
                    "country": j.get("country") or "",
                    "country_code": j.get("countryCode") or "",
                    "lat": j.get("lat"),
                    "lon": j.get("lon"),
                    "source": "ip-api",
                }
    except Exception:
        pass

    # Fallback: ipwho.is
    try:
        url = "https://ipwho.is/" + (client_ip or "")
        async with httpx.AsyncClient(timeout=timeout) as c:
            r = await c.get(url)
            j = r.json()
            if j.get("success", True) is not False:
                return {
                    "city": j.get("city") or "",
                    "country": j.get("country") or "",
                    "country_code": j.get("country_code") or "",
                    "lat": j.get("latitude"),
                    "lon": j.get("longitude"),
                    "source": "ipwho",
                }
    except Exception:
        pass

    return {"city": "", "country": "", "country_code": "", "lat": None, "lon": None, "source": "none"}


@router.get("/weather")
async def weather(lat: float, lon: float):
    """Server-side current-weather proxy.

    Uses Open-Meteo (free, no key, HTTPS, CORS-friendly) but we proxy
    server-side so the call works the same on web (HTTPS) and on
    Capacitor Android (regardless of cleartext config). Returns:
        { temp_c: number, weather_code: int, source: 'open-meteo' }
    """
    timeout = httpx.Timeout(5.0)
    try:
        url = (
            "https://api.open-meteo.com/v1/forecast"
            f"?latitude={lat}&longitude={lon}&current=temperature_2m,weather_code"
        )
        async with httpx.AsyncClient(timeout=timeout) as c:
            r = await c.get(url)
            j = r.json()
            cur = j.get("current") or {}
            return {
                "temp_c": cur.get("temperature_2m"),
                "weather_code": cur.get("weather_code"),
                "source": "open-meteo",
            }
    except Exception:
        return {"temp_c": None, "weather_code": None, "source": "none"}


@auth_router.get("/shared-profiles")
async def list_shared_profiles(request: Request, user=Depends(get_current_user)):
    """Return the admin-configured shared profiles. REQUIRES login —
    guests intentionally cannot see any shared-account info.

    BUG-7 FIX (2026-05): if the user's xtream_mode is "own" (per-user),
    return an EMPTY profiles list so the frontend never injects shared
    content into their local store. Only "shared" (global) mode users
    should see the admin-configured profiles."""
    db = get_db()

    # Check user's xtream_mode — "own" users must get empty list
    user_doc = await db.users.find_one({"id": user["id"]}, {"_id": 0})
    if user_doc and user_doc.get("xtream_mode") == "own":
        return {"profiles": [], "xtream_mode": "own"}

    settings = await _get_settings_doc(db)
    profiles = settings.get("shared_profiles") or []
    proxy_enabled = settings.get("proxy_enabled", False)
    return {"profiles": profiles, "proxy_enabled": proxy_enabled}
