"""Main PyView application for FenLiu."""

from __future__ import annotations

import traceback
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from pathlib import Path
from typing import Any

import pyview.pyview
from pyview import PyView
from pyview.template import RootTemplateContext
from starlette.requests import Request
from starlette.responses import JSONResponse
from starlette.staticfiles import StaticFiles

from fenliu.api import api_router
from fenliu.config import settings
from fenliu.database import get_db
from fenliu.liveviews import ReviewLiveView
from fenliu.logging import get_logger
from fenliu.logging import setup_logging
from fenliu.middleware import APIKeyMiddleware
from fenliu.models import AppSetting
from fenliu.services.api_key import generate_api_key
from fenliu.services.api_key import get_api_key
from fenliu.services.blocklist_cache import initialize_cache
from fenliu.services.scheduler import start_scheduler
from fenliu.services.scheduler import stop_scheduler
from fenliu.views.dashboard import dashboard
from fenliu.views.review import queue_preview_page
from fenliu.views.settings import settings_page
from fenliu.views.settings import update_settings
from fenliu.views.stats import post_details
from fenliu.views.stats import stats_page
from fenliu.views.streams import streams_page

logger = get_logger(__name__)

# PyView bug workaround: Patch liveview_container to handle UnconnectedSocket
_original_liveview_container = pyview.pyview.liveview_container


async def _patched_liveview_container(template: Any, view_lookup: Any, request: Request) -> Any:
    """Patched version of liveview_container that handles UnconnectedSocket."""
    logger.debug(f"_patched_liveview_container: path={request.url.path}")
    try:
        result = await _original_liveview_container(template, view_lookup, request)
        logger.debug(f"_patched_liveview_container: success for {request.url.path}")
        return result
    except ValueError as e:
        logger.debug(f"_patched_liveview_container: No LiveView for {request.url.path} - {e}")
        # No LiveView found for this path - this is expected for regular HTTP routes
        # Let the request continue to regular HTTP routes
        raise
    except Exception as e:
        # Log any other errors
        logger.error(f"Error in patched liveview_container: {e}")
        logger.error(traceback.format_exc())
        raise


# Apply the patch
pyview.pyview.liveview_container = _patched_liveview_container  # type: ignore


@asynccontextmanager
async def lifespan(_app: PyView) -> AsyncIterator[None]:
    """Lifespan context manager for PyView application."""
    # Restore logging config — uvicorn resets handlers during startup
    setup_logging(debug=settings.debug, log_dir=settings.log_dir)
    logger.info("Starting FenLiu application...")
    logger.debug(f"Database URL: {settings.database_url}")
    logger.debug(f"Debug mode: {settings.debug}")

    # Auto-generate API key on first startup if none exists
    with get_db() as db:
        if get_api_key(db) is None:
            new_key = generate_api_key()
            db.add(AppSetting(key="api_key", value=new_key))
            db.commit()

    # Initialize blocklist cache for fast eligibility checks
    try:
        with get_db() as db:
            initialize_cache(db)
            logger.info("Blocklist cache initialized")
    except Exception as e:
        logger.error(f"Failed to initialize blocklist cache: {e}", exc_info=True)
        raise

    # Start background scheduler for stream fetches
    try:
        await start_scheduler()
    except Exception as e:
        logger.error(f"Failed to start background scheduler: {e}", exc_info=True)
        raise

    logger.info(f"FenLiu {settings.app_version} started successfully")
    yield

    # Shutdown: Stop background scheduler
    logger.debug("lifespan: shutting down background scheduler")
    try:
        await stop_scheduler()
    except Exception as e:
        logger.error(f"Error stopping background scheduler: {e}", exc_info=True)

    logger.debug("lifespan: shutting down FenLiu application")


# Create PyView application
app = PyView(
    lifespan=lifespan,
    debug=settings.debug,
)

# Add API key authentication middleware
app.add_middleware(APIKeyMiddleware)  # type: ignore[arg-type]

# Mount static files directory
app.mount("/static", StaticFiles(directory=Path(__file__).parent / "static"), name="static")


def custom_root_template(context: RootTemplateContext) -> str:
    """Return a custom root template with Tailwind CSS and Font Awesome."""
    # Use context title if provided, otherwise use default
    title = context.get("title") or f"{settings.app_name} v{settings.app_version}"
    render_title = title + " | LiveView" if title else "LiveView"

    return f'''
<!DOCTYPE html>
<html lang="en">
    <head>
      <title data-suffix=" | LiveView">{render_title}</title>
      <meta name="csrf-token" content="{context["csrf_token"]}" />
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

      <!-- Tailwind CSS -->
      <script src="https://cdn.tailwindcss.com"></script>

      <!-- Font Awesome -->
      <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" />

      <!-- Review Page Styles -->
      <link rel="stylesheet" href="/static/styles/review.css" />

      <!-- Favicon -->
      <link rel="icon" href="/static/FenLiu.png" type="image/png" />
      <link rel="apple-touch-icon" href="/static/FenLiu.png" />

      <script defer type="text/javascript" src="/static/assets/app.js"></script>
      {"\n".join(context["additional_head_elements"])}
    </head>
    <body>
      <div
        data-phx-main="true"
        data-phx-session="{context["session"]}"
        data-phx-static=""
        id="phx-{context["id"]}"
        >
        {context["content"]}
      </div>
    </body>
</html>
'''


# Customize root template
app.rootTemplate = custom_root_template


async def health_check(_request: Request) -> JSONResponse:
    """Health check endpoint."""
    return JSONResponse(
        {
            "status": "healthy",
            "app": settings.app_name,
            "version": settings.app_version,
        }
    )


async def app_info(_request: Request) -> JSONResponse:
    """Application information endpoint."""
    return JSONResponse(
        {
            "app": settings.app_name,
            "version": settings.app_version,
            "description": "Fediverse content stream filtering system",
            "inspiration": "Dujiangyan irrigation system (256 BC)",
        }
    )


# Add API endpoints (RESTful)
app.mount("/api", api_router)

# Register HTTP routes
app.add_route("/", dashboard, methods=["GET"])
app.add_route("/streams", streams_page, methods=["GET"])
app.add_live_view("/review", ReviewLiveView)
app.add_route("/stats", stats_page, methods=["GET"])
app.add_route("/posts/{post_id}", post_details, methods=["GET"])
app.add_route("/settings", settings_page, methods=["GET"])
app.add_route("/settings", update_settings, methods=["POST"])
app.add_route("/queue", queue_preview_page, methods=["GET"])
app.add_route("/health", health_check, methods=["GET"])
app.add_route("/info", app_info, methods=["GET"])
