import { errorDetails } from "./ops/monitor";
import { createAccountRoutes } from "./account/routes";
import { createHabitRoutes } from "./habits/routes";
import { ApiError } from "./habits/service";
import { Hono } from "hono";
import { sql } from "drizzle-orm";
import { createAuth, type AppDatabase, type AuthEnv } from "./auth";
import type { AuthConfig } from "./auth/config";
import type { FetchDiscord } from "./auth/discord";
import { createSharingRoutes, type DiscordFetch } from "./sharing/routes";
import type { DiscordSharingConfig } from "./sharing/config";

export function createApi(db: AppDatabase, config: AuthConfig, request?: FetchDiscord, now?: () => number, discordRequest?: DiscordFetch, sharingConfig: DiscordSharingConfig = { token: "", channelId: "" }, operations: { healthy?: () => boolean; log?: (event: Record<string, unknown>) => void } = {}) {
  const app = new Hono<AuthEnv>();
  app.use("*", async (c, next) => {
    const requestId = crypto.randomUUID();
    c.set("requestId", requestId); c.header("X-Request-ID", requestId);
    await next();
  });
  const auth = createAuth(db, config, request, now);
  app.get("/api/health", c => {
    c.header("Cache-Control", "no-store");
    db.get(sql`SELECT 1`);
    if (operations.healthy && !operations.healthy()) return c.json({ status: "degraded" }, 503);
    return c.json({ status: "ok" });
  });
  app.route("/api/auth", auth.routes);
  app.route("/api/account", createAccountRoutes(db, auth, now ?? Date.now));
  app.get("/api/me", auth.requireAuth, c => c.json(c.get("user")));
  app.route("/api", createHabitRoutes(db, auth, now ?? Date.now));
  app.route("/api/sharing", createSharingRoutes(db, auth, sharingConfig, now ?? Date.now, discordRequest));
  app.notFound(c => c.json({ error: "Not found" }, 404));
  app.onError((_error, c) => {
    c.header("Cache-Control", "no-store");
    if (_error instanceof ApiError) return c.json({ error: _error.message }, _error.status);
    const requestId = c.get("requestId");
    const event = { event: "request_failed", timestamp: new Date().toISOString(), requestId, method: c.req.method,
      route: c.req.routePath, ...errorDetails(_error) };
    (operations.log ?? (event => console.error(JSON.stringify(event))))(event);
    return c.json({ error: "Internal server error", requestId }, 500);
  });
  return app;
}
