import type { TaskTreeCommand } from "./contracts.ts";

export function createTaskTreeHttpApp(options: { dispatch: (command: TaskTreeCommand) => Promise<any>; close?: () => Promise<void> }) {
  return {
    async fetch(request: Request): Promise<Response> {
      const url = new URL(request.url);
      if (url.pathname === "/health/live") return json(200, { ok: true, serviceId: "hwlab-tasktree-api", status: "live" });
      if (url.pathname === "/health/ready") return resultResponse(await options.dispatch({ operation: "health" }));
      if (url.pathname === "/v1/tasktree/groups" && request.method === "GET") return resultResponse(await options.dispatch({ operation: "group.list" }));
      if (url.pathname === "/v1/tasktree/overview" && request.method === "GET") return resultResponse(await options.dispatch({ operation: "group.overview" }));
      if (url.pathname === "/v1/tasktree/groups" && request.method === "POST") {
        const body = await bodyObject(request);
        return resultResponse(await options.dispatch({ operation: "group.create", name: text(body.name), description: text(body.description) }), 201);
      }
      const timeline = /^\/v1\/tasktree\/groups\/([^/]+)\/timeline$/u.exec(url.pathname);
      if (timeline && request.method === "GET") return resultResponse(await options.dispatch({ operation: "timeline.get", groupId: decodeURIComponent(timeline[1]) }));
      if (url.pathname === "/v1/tasktree/commands" && request.method === "POST") {
        return resultResponse(await options.dispatch(await bodyObject(request) as TaskTreeCommand));
      }
      return json(404, { ok: false, error: { code: "not_found", message: "TaskTree route was not found" } });
    },
    close: options.close ?? (async () => {})
  };
}

function resultResponse(result: any, successStatus = 200) {
  const status = result?.ok === true ? successStatus : result?.error?.code?.includes("not_found") ? 404 : 400;
  return json(status, result);
}
async function bodyObject(request: Request): Promise<Record<string, any>> {
  const body = await request.json().catch(() => null);
  if (!body || typeof body !== "object" || Array.isArray(body)) throw Object.assign(new Error("JSON object body is required"), { code: "invalid_json" });
  return body as Record<string, any>;
}
function text(value: unknown) { return String(value ?? ""); }
function json(status: number, body: unknown) { return Response.json(body, { status, headers: { "cache-control": "no-store" } }); }
