/**
 * GET    /api/workspaces/[slug]/apps/[uuid]  — app details
 * PATCH  /api/workspaces/[slug]/apps/[uuid]  — update fields (name/branch/build config)
 * DELETE /api/workspaces/[slug]/apps/[uuid]?confirm=<name>
 *                                             — destroy app. Volumes kept by default.
 *
 * All verify the app's project uuid matches the workspace's before
 * acting. DELETE additionally requires `?confirm=<exact-resource-name>`
 * to prevent AI-driven accidents.
 */

import { NextResponse } from "next/server";
import { requireWorkspacePrincipal } from "@/lib/auth/workspace-auth";
import {
  getApplicationInProject,
  projectUuidOf,
  TenantError,
  updateApplication,
  deleteApplication,
} from "@/lib/coolify";

export async function GET(
  request: Request,
  { params }: { params: Promise<{ slug: string; uuid: string }> },
) {
  const { slug, uuid } = await params;
  const principal = await requireWorkspacePrincipal(request, {
    targetSlug: slug,
  });
  if (principal instanceof NextResponse) return principal;

  const ws = principal.workspace;
  if (!ws.coolify_project_uuid) {
    return NextResponse.json(
      { error: "Workspace has no Coolify project yet" },
      { status: 503 },
    );
  }

  try {
    const app = await getApplicationInProject(uuid, ws.coolify_project_uuid);
    return NextResponse.json({
      uuid: app.uuid,
      name: app.name,
      status: app.status,
      fqdn: app.fqdn ?? null,
      domains: app.domains ?? null,
      gitRepository: app.git_repository ?? null,
      gitBranch: app.git_branch ?? null,
      projectUuid: projectUuidOf(app),
    });
  } catch (err) {
    if (err instanceof TenantError) {
      return NextResponse.json({ error: err.message }, { status: 403 });
    }
    return NextResponse.json(
      {
        error: "Coolify request failed",
        details: err instanceof Error ? err.message : String(err),
      },
      { status: 502 },
    );
  }
}

export async function PATCH(
  request: Request,
  { params }: { params: Promise<{ slug: string; uuid: string }> },
) {
  const { slug, uuid } = await params;
  const principal = await requireWorkspacePrincipal(request, {
    targetSlug: slug,
  });
  if (principal instanceof NextResponse) return principal;

  const ws = principal.workspace;
  if (!ws.coolify_project_uuid) {
    return NextResponse.json(
      { error: "Workspace has no Coolify project yet" },
      { status: 503 },
    );
  }

  // Verify tenancy first (400-style fail fast on cross-tenant access).
  try {
    await getApplicationInProject(uuid, ws.coolify_project_uuid);
  } catch (err) {
    if (err instanceof TenantError) {
      return NextResponse.json({ error: err.message }, { status: 403 });
    }
    return NextResponse.json({ error: "App not found" }, { status: 404 });
  }

  let body: Record<string, unknown> = {};
  try {
    body = await request.json();
  } catch {
    return NextResponse.json({ error: "Invalid JSON body" }, { status: 400 });
  }

  // Whitelist which Coolify fields we expose to AI-level callers.
  // Domains are managed via the dedicated /domains subroute.
  const allowed = new Set([
    "name",
    "description",
    "git_repository",
    "git_branch",
    "build_pack",
    "ports_exposes",
    "install_command",
    "build_command",
    "start_command",
    "base_directory",
    "dockerfile_location",
    "is_auto_deploy_enabled",
    "is_force_https_enabled",
    "static_image",
  ]);
  const patch: Record<string, unknown> = {};
  for (const [k, v] of Object.entries(body)) {
    if (allowed.has(k) && v !== undefined) patch[k] = v;
  }
  if (Object.keys(patch).length === 0) {
    return NextResponse.json(
      { error: "No updatable fields in body" },
      { status: 400 },
    );
  }

  try {
    await updateApplication(uuid, patch);
    return NextResponse.json({ ok: true, uuid });
  } catch (err) {
    return NextResponse.json(
      {
        error: "Coolify update failed",
        details: err instanceof Error ? err.message : String(err),
      },
      { status: 502 },
    );
  }
}

export async function DELETE(
  request: Request,
  { params }: { params: Promise<{ slug: string; uuid: string }> },
) {
  const { slug, uuid } = await params;
  const principal = await requireWorkspacePrincipal(request, {
    targetSlug: slug,
  });
  if (principal instanceof NextResponse) return principal;

  const ws = principal.workspace;
  if (!ws.coolify_project_uuid) {
    return NextResponse.json(
      { error: "Workspace has no Coolify project yet" },
      { status: 503 },
    );
  }

  // Resolve the app and verify tenancy.
  let app;
  try {
    app = await getApplicationInProject(uuid, ws.coolify_project_uuid);
  } catch (err) {
    if (err instanceof TenantError) {
      return NextResponse.json({ error: err.message }, { status: 403 });
    }
    return NextResponse.json({ error: "App not found" }, { status: 404 });
  }

  // Require `?confirm=<exact app name>` to prevent accidental destroys.
  const url = new URL(request.url);
  const confirm = url.searchParams.get("confirm");
  if (confirm !== app.name) {
    return NextResponse.json(
      {
        error: "Confirmation required",
        hint: `Pass ?confirm=${app.name} to delete this app`,
      },
      { status: 409 },
    );
  }

  // Default: preserve volumes (user data). Caller can opt in.
  const deleteVolumes = url.searchParams.get("delete_volumes") === "true";
  const deleteConfigurations =
    url.searchParams.get("delete_configurations") !== "false";
  const deleteConnectedNetworks =
    url.searchParams.get("delete_connected_networks") !== "false";
  const dockerCleanup = url.searchParams.get("docker_cleanup") !== "false";

  try {
    await deleteApplication(uuid, {
      deleteConfigurations,
      deleteVolumes,
      deleteConnectedNetworks,
      dockerCleanup,
    });
    return NextResponse.json({
      ok: true,
      deleted: { uuid, name: app.name, volumesKept: !deleteVolumes },
    });
  } catch (err) {
    return NextResponse.json(
      {
        error: "Coolify delete failed",
        details: err instanceof Error ? err.message : String(err),
      },
      { status: 502 },
    );
  }
}
