/**
 * Structured logger for API handlers.
 *
 * Why this exists: `console.log` everywhere in 159 route files is impossible
 * to grep through. With a request-scoped `turnId` (or any other correlation
 * id), prod incidents go from "search by guess" to "ripgrep one ID, get the
 * whole timeline."
 *
 * Output shape (single line, JSON, prod-friendly):
 *   {"ts":"2026-05-17T20:00:00.000Z","level":"info","route":"api.chat",
 *    "turnId":"…","projectId":"…","user":"mark@…","msg":"…","ctx":{…}}
 *
 * In dev, we prefix with a coloured tag and pretty-print `ctx` for eyeball-
 * ability. In prod, single-line JSON so a log shipper can parse it.
 */

export type LogLevel = "debug" | "info" | "warn" | "error";

export interface LogContext {
  route?: string;
  turnId?: string;
  projectId?: string;
  workspaceSlug?: string;
  user?: string;
  userId?: string;
  [k: string]: unknown;
}

const isDev = process.env.NODE_ENV !== "production";

function emit(level: LogLevel, msg: string, ctx: LogContext = {}) {
  const ts = new Date().toISOString();
  const { route, turnId, projectId, workspaceSlug, user, userId, ...rest } = ctx;
  const base = { ts, level, msg, route, turnId, projectId, workspaceSlug, user, userId };
  if (isDev) {
    const tag = level === "error" ? "✗" : level === "warn" ? "!" : level === "debug" ? "·" : "→";
    const idStr = turnId ? ` [${turnId.slice(0, 8)}]` : "";
    const routeStr = route ? ` ${route}` : "";
    const extra = Object.keys(rest).length ? ` ${JSON.stringify(rest)}` : "";
    // eslint-disable-next-line no-console
    console[level === "debug" ? "log" : level](`${tag}${routeStr}${idStr} ${msg}${extra}`);
    return;
  }
  const line = JSON.stringify({ ...base, ...rest });
  // eslint-disable-next-line no-console
  (console[level === "debug" ? "log" : level] as (m: string) => void)(line);
}

/**
 * Create a logger pre-bound to a request context. Pass through `info()` /
 * `warn()` / `error()` / `debug()` and every line carries the same
 * `turnId` / `projectId` / `route`.
 */
export function makeLogger(base: LogContext) {
  return {
    debug: (msg: string, ctx: LogContext = {}) => emit("debug", msg, { ...base, ...ctx }),
    info: (msg: string, ctx: LogContext = {}) => emit("info", msg, { ...base, ...ctx }),
    warn: (msg: string, ctx: LogContext = {}) => emit("warn", msg, { ...base, ...ctx }),
    error: (msg: string, ctx: LogContext = {}) => emit("error", msg, { ...base, ...ctx }),
    child(extra: LogContext) {
      return makeLogger({ ...base, ...extra });
    },
  };
}

export const log = {
  debug: (msg: string, ctx: LogContext = {}) => emit("debug", msg, ctx),
  info: (msg: string, ctx: LogContext = {}) => emit("info", msg, ctx),
  warn: (msg: string, ctx: LogContext = {}) => emit("warn", msg, ctx),
  error: (msg: string, ctx: LogContext = {}) => emit("error", msg, ctx),
};
