import logging

import sentry_sdk
from fastapi import FastAPI
from sentry_sdk.integrations.fastapi import FastApiIntegration
from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration
from sentry_sdk.integrations.starlette import StarletteIntegration
from sqlalchemy import text

from app.api.admin import router as admin_router
from app.api.admin_html import mount_static
from app.api.admin_html import router as admin_html_router
from app.api.blacklist import router as blacklist_router
from app.api.bug_reports import router as bug_reports_router
from app.api.expo_updates import router as expo_updates_router
from app.api.favorites import router as favorites_router
from app.api.me import router as me_router
from app.api.movies import router as movies_router
from app.api.playback import movies_router as movies_playback_router
from app.api.playback import router as playback_router
from app.api.playback_events import router as playback_events_router
from app.api.saved_searches import router as saved_searches_router
from app.api.scene_favorites import router as scene_favorites_router
from app.api.scenes import router as scenes_router
from app.api.seo import router as seo_router
from app.api.sources import router as sources_router
from app.api.stream_proxy import router as stream_proxy_router
from app.api.taxonomies import router as taxonomies_router
from app.api.watch import router as watch_router
from app.config import get_settings
from app.db import session_scope

_settings = get_settings()
logging.basicConfig(level=_settings.log_level)

# Sentry: init przed FastAPI() żeby SDK przechwycił request handlery od pierwszego.
# Pusty DSN → SDK no-op (dev/local). Integracje: FastApi (request context, transactions),
# Starlette (middleware-level errors), SQLAlchemy (slow queries jako spans).
if _settings.sentry_dsn:
    def _sentry_before_send(event, hint):
        """Filter expected/transient HTTPException z proxy + playback resolve.

        Sentry FastAPI integration loguje WSZYSTKIE HTTPException jako error.
        Dla nas 502/503/504 to expected behavior gdy upstream CDN unreachable
        albo extractor zwraca None (legitnie). Spam-flooduje issue list
        (GOON-3 16ev/5h, GOON-G 8ev, GOON-4 6ev).
        """
        exc_info = hint.get("exc_info") if hint else None
        if not exc_info:
            return event
        exc = exc_info[1]
        from fastapi import HTTPException as _HTTPExc
        if isinstance(exc, _HTTPExc) and exc.status_code in {502, 503, 504}:
            return None  # drop
        return event

    sentry_sdk.init(
        dsn=_settings.sentry_dsn,
        environment=_settings.sentry_environment,
        traces_sample_rate=_settings.sentry_traces_sample_rate,
        # send_default_pii=False — bezpieczne, headers/cookies/IP nie idą do Sentry.
        # Zostawiamy default (False) bo niektóre tube'y mają potencjalnie wrażliwe URL'e.
        integrations=[
            StarletteIntegration(transaction_style="endpoint"),
            FastApiIntegration(transaction_style="endpoint"),
            SqlalchemyIntegration(),
        ],
        before_send=_sentry_before_send,
        release="goon@0.1.8",
    )

app = FastAPI(title="goon", version="0.1.8")
app.include_router(scenes_router)
app.include_router(sources_router)
app.include_router(movies_router)
app.include_router(playback_router)
app.include_router(playback_events_router)
app.include_router(movies_playback_router)
app.include_router(scene_favorites_router)
app.include_router(stream_proxy_router)
app.include_router(taxonomies_router)
app.include_router(favorites_router)
app.include_router(blacklist_router)
app.include_router(bug_reports_router)
app.include_router(saved_searches_router)
app.include_router(expo_updates_router)
app.include_router(watch_router)
app.include_router(me_router)
app.include_router(admin_router)
app.include_router(admin_html_router)
app.include_router(seo_router)
mount_static(app)


@app.get("/healthz")
def healthz() -> dict[str, str]:
    return {"status": "ok"}


@app.get("/version")
def version() -> dict[str, str | None]:
    """Mobile sprawdza po starcie żeby wykryć dostępność nowszej wersji APK.

    Zwraca:
      - `version`: kanoniczna wersja serwera (źródło prawdy o latest APK)
      - `apk_url`: bezpośredni link do najnowszego APK (self-hosted) lub None
        gdy tylko external (GitHub Releases). Mobile otwiera w browser przy update.

    APK jest serwowany ze statycznego endpointu `/static/app-debug.apk` jeśli
    istnieje (gradle build → scp na VPS → tu serwujemy). Brak pliku → `apk_url=None`,
    mobile pokazuje tylko "newer version available" bez direct link.
    """
    import os
    from pathlib import Path

    apk_path = Path(__file__).resolve().parent / "static" / "app-release.apk"
    apk_url: str | None = None
    if apk_path.exists():
        # `BACKEND_PUBLIC_URL` z env to URL pod którym mobile może hit'nąć backend
        # (production: https://goon.example.com lub IP:port). Default — relatywny URL,
        # mobile sklei z baseUrl.
        public_url = os.environ.get("BACKEND_PUBLIC_URL", "").rstrip("/")
        apk_url = f"{public_url}/static/app-release.apk" if public_url else "/static/app-release.apk"
    return {"version": "0.2.1", "apk_url": apk_url}


@app.get("/readyz")
def readyz() -> dict[str, object]:
    try:
        with session_scope() as session:
            session.execute(text("SELECT 1"))
        return {"status": "ready", "db": "ok"}
    except Exception as exc:
        return {"status": "degraded", "db": "error", "error": str(exc)}
