# Load environment variables from project root .env (must be first!)
import os
import sys
import logging
from pathlib import Path
from dotenv import load_dotenv

# Force UTF-8 on Windows console streams so OpenGrep's logger doesn't crash on cp1252.
# Must run before any logging or OpenGrep import.  No-op on macOS/Linux.
if sys.platform == 'win32':
    try:
        if sys.stdout is not None:
            sys.stdout.reconfigure(encoding='utf-8', errors='replace')
        if sys.stderr is not None:
            sys.stderr.reconfigure(encoding='utf-8', errors='replace')
    except Exception:
        pass  # frozen builds or redirected streams may not support reconfigure

# Fix SSL certificate path for PyInstaller frozen builds (required by httpx/litellm)
if getattr(sys, 'frozen', False):
    import certifi
    _cert_file = os.path.join(sys._MEIPASS, 'certifi', 'cacert.pem')
    if os.path.exists(_cert_file):
        os.environ.setdefault('SSL_CERT_FILE', _cert_file)
        os.environ.setdefault('REQUESTS_CA_BUNDLE', _cert_file)

# In development, load .env from project root (parent of rivet_server/)
# In production (PyInstaller), env vars are passed by Electron
_project_root = Path(__file__).parent.parent.parent
_env_file = _project_root / ".env"
if _env_file.exists():
    load_dotenv(_env_file)

# Configure structured logging before anything else
from app.utils.logging_config import configure_logging, RequestLoggingMiddleware
configure_logging()

from fastapi import FastAPI, Request, HTTPException, Depends
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import Response
from app.config.config import ALLOWED_ORIGINS
from app.api import root, data, scan, code_analysis, config_analyzer, ai_fix, patches, auth, license, dashboard, reports
from app.database import create_db_and_tables
import asyncio

# Fix Windows asyncio event loop for subprocess support
if sys.platform == 'win32':
    asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())

logger = logging.getLogger(__name__)

# Auth mode: "desktop" (no auth, default), "server" (JWT required)
AUTH_MODE = os.getenv("AUTH_MODE", "desktop")


class ElectronOriginMiddleware(BaseHTTPMiddleware):
    """Allow null origin for local Electron app in desktop mode only."""

    async def dispatch(self, request: Request, call_next):
        origin = request.headers.get("origin")
        if origin == "null" and AUTH_MODE == "desktop":
            client_host = request.client.host if request.client else None
            if client_host in ("127.0.0.1", "::1", "localhost"):
                response = await call_next(request)
                response.headers["Access-Control-Allow-Origin"] = "null"
                response.headers["Access-Control-Allow-Credentials"] = "true"
                response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS"
                response.headers["Access-Control-Allow-Headers"] = "Authorization, Content-Type, X-Google-API-Key, X-LLM-Key, X-Requested-With"
                return response
        return await call_next(request)


app = FastAPI()

# Create database tables and configure audit logging on startup
@app.on_event("startup")
def on_startup():
    from app.migrations import run_migrations
    try:
        run_migrations()
    except Exception as e:
        logger.critical(
            f"Database migration failed: {e}. "
            "The database may be locked or corrupt. "
            "Try deleting database.db and restarting the application."
        )
        # Continue — individual requests will fail gracefully rather than blocking startup

    try:
        create_db_and_tables()
    except Exception as e:
        logger.critical(
            f"Failed to create database tables: {e}. "
            "Check that database.db is not locked by another process."
        )

    # Configure audit logger
    from app.utils.audit_logger import configure_audit_logging
    configure_audit_logging()

    # Validate license on startup
    try:
        from app.services.rivet_startup_license_check import validate_license_on_startup
        validate_license_on_startup()
    except Exception as e:
        logger.error(f"License validation failed on startup: {e}")
        # Continue startup anyway in lenient mode

# Request logging middleware (outermost — added first, runs last)
app.add_middleware(RequestLoggingMiddleware)

# Electron null-origin middleware (must be added BEFORE CORSMiddleware)
app.add_middleware(ElectronOriginMiddleware)

# Add CORS middleware for cross-origin requests
app.add_middleware(
    CORSMiddleware,
    allow_origins=ALLOWED_ORIGINS,
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
    allow_headers=["Authorization", "Content-Type", "X-Google-API-Key", "X-LLM-Key", "X-Requested-With"],
)

# Conditional auth: "server" mode requires JWT, "desktop" mode is open
if AUTH_MODE == "server":
    from app.auth import get_current_user
    protected_dependencies = [Depends(get_current_user)]
    logger.info("Server auth mode: JWT authentication required for API routes")
else:
    protected_dependencies = []
    logger.info("Desktop auth mode: API routes are unprotected (local access only)")

app.include_router(root.router)
app.include_router(auth.router, prefix="/api")  # Keep auth routes available for future use
app.include_router(data.router, prefix="/data")
app.include_router(scan.router, prefix="/api", dependencies=protected_dependencies)
app.include_router(code_analysis.router, prefix="/api", dependencies=protected_dependencies)
app.include_router(config_analyzer.router, prefix="/api", dependencies=protected_dependencies)
app.include_router(ai_fix.router, prefix="/api", dependencies=protected_dependencies)
app.include_router(patches.router, prefix="/api", dependencies=protected_dependencies)
app.include_router(license.router, prefix="/api")
from app.api import trial
app.include_router(trial.router, prefix="/api")
app.include_router(dashboard.router, prefix="/api", dependencies=protected_dependencies)
app.include_router(reports.router, prefix="/api", dependencies=protected_dependencies)

# Import settings router
from app.api import settings

# Add settings router
app.include_router(settings.router)


@app.exception_handler(Exception)
async def unhandled_exception_handler(request: Request, exc: Exception) -> JSONResponse:
    """Catch-all for any exception not handled by a route's own error handling."""
    logger.exception(f"Unhandled exception on {request.method} {request.url.path}")
    return JSONResponse(
        status_code=500,
        content={"detail": "An unexpected error occurred. Please check the application logs."},
    )
