/**
 * Session Authentication Middleware
 *
 * Validates session cookies for UI authentication.
 */

import type { Context, Next } from "hono";
import { getCookie } from "hono/cookie";
import { getDb } from "@/db";
import { AppError } from "@/lib/errors";
import { getLogger } from "@/runtime/logger";
import { SessionService } from "@/services/session.service";
import type { Env } from "@/types/env";

const SESSION_COOKIE_NAME = "sdp_session";

/**
 * Session authentication middleware
 * Validates session cookie and sets auth context
 */
export function sessionAuthMiddleware() {
  return async (c: Context<{ Bindings: Env }>, next: Next) => {
    const sessionId = getCookie(c, SESSION_COOKIE_NAME);

    if (!sessionId) {
      throw new AppError("UNAUTHORIZED", "Session required");
    }

    const sessionService = new SessionService(getDb(c.env));
    const cachedSession = await sessionService.getSession(sessionId);

    if (!cachedSession) {
      throw new AppError("UNAUTHORIZED", "Invalid or expired session");
    }

    // Set session context
    c.set("session", cachedSession);

    // Update last activity (fire and forget)
    updateLastActivity(getDb(c.env), sessionId);

    await next();
  };
}

/**
 * Optional session auth - doesn't fail if no session provided
 */
export function optionalSessionAuth() {
  return async (c: Context<{ Bindings: Env }>, next: Next) => {
    const sessionId = getCookie(c, SESSION_COOKIE_NAME);

    if (sessionId) {
      try {
        const sessionService = new SessionService(getDb(c.env));
        const cachedSession = await sessionService.getSession(sessionId);

        if (cachedSession) {
          c.set("session", cachedSession);
          updateLastActivity(getDb(c.env), sessionId);
        }
      } catch {
        // Ignore errors for optional auth
      }
    }

    await next();
  };
}

/**
 * Update last activity timestamp (fire and forget)
 */
function updateLastActivity(db: DatabaseClient, sessionId: string) {
  db.prepare("UPDATE sessions SET last_activity_at = datetime('now') WHERE id = ?")
    .bind(sessionId)
    .run()
    .catch((err) => getLogger().error({ error: err }, "Failed to update session activity"));
}
