import { NextRequest, NextResponse } from "next/server";
import { getDb } from "@/lib/db";
import { Dirent, existsSync, mkdirSync, readdirSync, rmSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { execSync } from "node:child_process";
import { randomUUID } from "node:crypto";
import "@/lib/sdk-init";
import { serverConfig, launchWikiGeneration } from "@optage/sdk";
import { PgWikiCheckpointStore } from "@/lib/wiki-checkpoint";

const REPOS_PATH = serverConfig.reposPath;

function selectImportedSourcePath(repoDir: string): string {
  const visibleEntries = readdirSync(repoDir, { withFileTypes: true }).filter(
    (entry: Dirent) =>
      entry.name !== "__upload.zip" &&
      entry.name !== "__MACOSX" &&
      !entry.name.startsWith("."),
  );

  const directories = visibleEntries.filter((entry) => entry.isDirectory());
  const files = visibleEntries.filter((entry) => entry.isFile());

  if (files.length === 0 && directories.length === 1) {
    return join(repoDir, directories[0].name);
  }

  return repoDir;
}

export async function GET() {
  const db = await getDb();
  const { rows } = await db.query(
    "SELECT id, name, source_type, source_path, source_origin, description, created_at, updated_at FROM repositories ORDER BY updated_at DESC"
  );
  return NextResponse.json(rows);
}

export async function POST(request: NextRequest) {
  const contentType = request.headers.get("content-type") || "";

  let name: string;
  let source_type: "path" | "zip" | "git";
  let description: string | undefined;
  let source_path: string | undefined;
  let git_url: string | undefined;
  let zipFile: File | null = null;

  if (contentType.includes("multipart/form-data")) {
    const formData = await request.formData();
    name = formData.get("name") as string;
    source_type = formData.get("source_type") as "path" | "zip" | "git";
    description = (formData.get("description") as string) || undefined;
    source_path = (formData.get("source_path") as string) || undefined;
    git_url = (formData.get("git_url") as string) || undefined;
    zipFile = formData.get("zip_file") as File | null;
  } else {
    const body = await request.json();
    name = body.name;
    source_type = body.source_type;
    description = body.description;
    source_path = body.source_path;
    git_url = body.git_url;
    zipFile = null;
  }

  if (!name || !source_type) {
    return NextResponse.json({ error: "name and source_type required" }, { status: 400 });
  }

  let sourcePath: string;
  let sourceOrigin: string;

  if (source_type === "path") {
    sourcePath = source_path || "";
    sourceOrigin = sourcePath;
    if (!sourcePath || !existsSync(sourcePath)) {
      return NextResponse.json({ error: "Directory does not exist" }, { status: 400 });
    }
  } else if (source_type === "zip") {
    if (!zipFile) {
      return NextResponse.json({ error: "zip_file required" }, { status: 400 });
    }
    const repoId = randomUUID();
    const repoDir = join(REPOS_PATH, repoId);
    mkdirSync(repoDir, { recursive: true });
    const zipPath = join(repoDir, "__upload.zip");
    const zipBuffer = Buffer.from(await zipFile.arrayBuffer());
    writeFileSync(zipPath, zipBuffer);
    try {
      execSync(`unzip -o "${zipPath}" -d "${repoDir}"`, {
        timeout: serverConfig.repositoryImport.zipExtractTimeoutMs,
      });
    } catch (err) {
      rmSync(zipPath, { force: true });
      return NextResponse.json(
        { error: `Failed to extract zip: ${err instanceof Error ? err.message : err}` },
        { status: 500 }
      );
    }
    rmSync(zipPath, { force: true });
    sourcePath = selectImportedSourcePath(repoDir);
    sourceOrigin = zipFile.name || "uploaded.zip";
  } else if (source_type === "git") {
    if (!git_url) {
      return NextResponse.json({ error: "git_url required" }, { status: 400 });
    }
    const repoId = randomUUID();
    const repoDir = join(REPOS_PATH, repoId);
    mkdirSync(REPOS_PATH, { recursive: true });
    try {
      execSync(`git clone --depth 1 "${git_url}" "${repoDir}"`, {
        timeout: serverConfig.repositoryImport.gitCloneTimeoutMs,
        stdio: "pipe",
      });
    } catch (err) {
      return NextResponse.json(
        { error: `Failed to clone: ${err instanceof Error ? err.message : err}` },
        { status: 500 }
      );
    }
    sourcePath = repoDir;
    sourceOrigin = git_url;
  } else {
    return NextResponse.json({ error: "Invalid source_type" }, { status: 400 });
  }

  const db = await getDb();
  const { rows } = await db.query(
    `INSERT INTO repositories (name, source_type, source_path, source_origin, description)
     VALUES ($1, $2, $3, $4, $5)
     RETURNING *`,
    [name, source_type, sourcePath, sourceOrigin, description || null]
  );

  // Generate wiki documentation in background (don't block the upload response)
  launchWikiGeneration(rows[0].id, sourcePath, new PgWikiCheckpointStore(rows[0].id));

  return NextResponse.json(rows[0], { status: 201 });
}
