"""FastAPI web frontend for LinkedIn Post Creation System."""
from contextlib import asynccontextmanager
from pathlib import Path

from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse, RedirectResponse, JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.middleware.gzip import GZipMiddleware
from loguru import logger

from src.config import settings
from src.web.admin import admin_router


@asynccontextmanager
async def lifespan(app: FastAPI):
    """Manage application lifecycle - startup and shutdown."""
    logger.info("Starting LinkedIn Post Creation System...")

    # Warm up Redis connection pool
    from src.services.redis_client import get_redis, close_redis
    await get_redis()

    # Register Telegram webhook if enabled
    if settings.telegram_enabled and settings.telegram_bot_token and settings.telegram_webhook_url:
        try:
            from src.services.telegram_service import telegram_service
            if telegram_service:
                webhook_url = f"{settings.telegram_webhook_url}/api/telegram/webhook"
                await telegram_service.register_webhook(webhook_url, settings.telegram_webhook_secret)
                logger.info("Telegram webhook registered")
        except Exception as e:
            logger.error(f"Failed to register Telegram webhook: {e}")

    # Start scheduler only when this process is the dedicated scheduler container
    scheduler = None
    if settings.scheduler_enabled:
        try:
            from src.database.client import DatabaseClient
            from src.services.scheduler_service import init_scheduler

            db = DatabaseClient()
            scheduler = init_scheduler(db, check_interval=60)
            await scheduler.start()
            logger.info("Scheduler started (dedicated process)")
        except Exception as e:
            logger.error(f"Failed to start scheduler: {e}")

    yield  # Application runs here

    logger.info("Shutting down LinkedIn Post Creation System...")
    if scheduler:
        await scheduler.stop()
        logger.info("Scheduler service stopped")

    await close_redis()


# Setup
app = FastAPI(title="LinkedIn Post Creation System", lifespan=lifespan)


class SecurityHeadersMiddleware(BaseHTTPMiddleware):
    """Add security headers to every response."""

    # CSP allows inline scripts/styles (app uses them extensively in Jinja2 templates).
    # frame-ancestors 'none' replaces X-Frame-Options for modern browsers.
    _CSP = (
        "default-src 'self'; "
        "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net; "
        "style-src 'self' 'unsafe-inline'; "
        "img-src 'self' data: blob: https://*.supabase.co https://supabase.onyva.dev https://*.linkedin.com https://media.licdn.com; "
        "connect-src 'self' https://*.supabase.co https://supabase.onyva.dev; "
        "font-src 'self' data:; "
        "frame-ancestors 'none'; "
        "base-uri 'self'; "
        "form-action 'self';"
    )

    async def dispatch(self, request, call_next):
        response = await call_next(request)
        h = response.headers
        h["X-Frame-Options"] = "DENY"
        h["X-Content-Type-Options"] = "nosniff"
        h["X-XSS-Protection"] = "1; mode=block"
        h["Referrer-Policy"] = "strict-origin-when-cross-origin"
        h["Permissions-Policy"] = "camera=(), microphone=(self), geolocation=()"
        h["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"
        h["Content-Security-Policy"] = self._CSP
        return response


class StaticCacheMiddleware(BaseHTTPMiddleware):
    """Set long-lived Cache-Control headers on static assets."""

    async def dispatch(self, request, call_next):
        response = await call_next(request)
        if request.url.path.startswith("/static/"):
            if request.url.path.endswith((".css", ".js")):
                response.headers["Cache-Control"] = "public, max-age=86400, stale-while-revalidate=3600"
            elif request.url.path.endswith((".png", ".jpg", ".jpeg", ".svg", ".ico", ".webp")):
                response.headers["Cache-Control"] = "public, max-age=604800, immutable"
            else:
                response.headers["Cache-Control"] = "public, max-age=3600"
        return response


# Middleware executes in reverse registration order (last added = outermost).
# Order: GZip compresses → StaticCache sets headers → SecurityHeaders sets headers.
app.add_middleware(SecurityHeadersMiddleware)
app.add_middleware(StaticCacheMiddleware)
app.add_middleware(GZipMiddleware, minimum_size=500)

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


def _load_env_file(path: Path) -> dict:
    """Load key=value pairs from a simple .env file."""
    data = {}
    if not path.exists():
        return data
    for line in path.read_text(encoding="utf-8").splitlines():
        line = line.strip()
        if not line or line.startswith("#") or "=" not in line:
            continue
        key, val = line.split("=", 1)
        data[key.strip()] = val.strip()
    return data


def _send_contact_email(payload: dict) -> bool:
    """Send contact email using landing.env SMTP config."""
    import smtplib
    from email.mime.text import MIMEText
    from email.mime.multipart import MIMEMultipart

    root = Path(__file__).resolve().parents[3]
    env_path = root / "landing" / "landing.env"
    if not env_path.exists():
        env_path = root / "landing.env"
    env = _load_env_file(env_path)

    host = env.get("SMTP_HOST", "")
    port = int(env.get("SMTP_PORT", "587") or 587)
    user = env.get("SMTP_USER", "")
    password = env.get("SMTP_PASSWORD", "")
    from_name = env.get("SMTP_FROM_NAME", "LinkedIn Post System")
    to_email = "team@onyva.de"

    if not host or not user or not password:
        logger.error("Contact email SMTP not configured (landing.env)")
        return False

    subject = "Neue Kontaktanfrage (Landing Page)"
    body = (
        f"Name: {payload.get('name','')}\n"
        f"E-Mail: {payload.get('email','')}\n"
        f"Mitarbeiter: {payload.get('team_size','')}\n"
        f"Posts/Monat: {payload.get('posts_per_month','')}\n"
        f"Nachricht:\n{payload.get('message','')}\n"
    )

    msg = MIMEMultipart()
    msg["From"] = f"{from_name} <{user}>"
    msg["To"] = to_email
    msg["Subject"] = subject
    msg.attach(MIMEText(body, "plain"))

    try:
        with smtplib.SMTP(host, port) as server:
            server.starttls()
            server.login(user, password)
            server.sendmail(user, to_email, msg.as_string())
        return True
    except Exception as exc:
        logger.error(f"Contact email failed: {exc}")
        return False


@app.post("/api/contact")
async def contact(request: Request):
    data = await request.json()
    required = ["name", "email", "team_size", "posts_per_month", "message"]
    for key in required:
        if not data.get(key):
            return JSONResponse({"ok": False, "error": f"Missing {key}"}, status_code=400)
    ok = _send_contact_email(data)
    if not ok:
        return JSONResponse({"ok": False, "error": "Email failed"}, status_code=500)
    return {"ok": True}


@app.get("/sw.js", include_in_schema=False)
async def service_worker():
    """Serve Service Worker from root scope so it can intercept all page requests."""
    response = FileResponse(Path(__file__).parent / "static/sw.js", media_type="application/javascript")
    response.headers["Service-Worker-Allowed"] = "/"
    response.headers["Cache-Control"] = "no-cache"
    return response


@app.api_route("/googledf500b0e0ed297ad.html", methods=["GET", "HEAD"], include_in_schema=False)
async def google_site_verification():
    """Serve Google Search Console ownership verification file."""
    verification_file = Path(__file__).resolve().parents[2] / "googledf500b0e0ed297ad.html"
    response = FileResponse(verification_file, media_type="text/html")
    response.headers["Cache-Control"] = "public, max-age=300"
    return response

# Include admin router (always available)
app.include_router(admin_router)

# Include user router if enabled
if settings.user_frontend_enabled:
    from src.web.user import user_router
    app.include_router(user_router)
else:
    # Root redirect only when user frontend is disabled
    @app.get("/")
    async def root():
        """Redirect root to admin frontend."""
        return RedirectResponse(url="/admin", status_code=302)


def run_web():
    """Run the web server."""
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)


if __name__ == "__main__":
    run_web()
