import { NextResponse } from "next/server";
import fs from "fs";
import path from "path";
import os from "os";

// Helper to recursively generate a tree nodes list for UI representation
interface TreeNode {
  name: string;
  path: string;
  type: "file" | "directory";
  children?: TreeNode[];
}

function getDirectoryTree(dirPath: string, depth = 0, maxDepth = 3): TreeNode[] {
  const normDirPath = dirPath.replace(/\\/g, "/");
  if (depth > maxDepth) return [];
  try {
    const items = fs.readdirSync(normDirPath, { withFileTypes: true });
    const nodes: TreeNode[] = [];

    for (const item of items) {
      // Skip hidden folders and build folders to keep explorer performant
      if (
        item.name.startsWith(".") ||
        item.name === "node_modules" ||
        item.name === "out" ||
        item.name === ".next" ||
        item.name === "dist"
      ) {
        continue;
      }

      const itemPath = path.join(normDirPath, item.name).replace(/\\/g, "/");
      if (item.isDirectory()) {
        nodes.push({
          name: item.name,
          path: itemPath,
          type: "directory",
          children: getDirectoryTree(itemPath, depth + 1, maxDepth),
        });
      } else {
        nodes.push({
          name: item.name,
          path: itemPath,
          type: "file",
        });
      }
    }

    // Sort: directories first, then files alphabetically
    return nodes.sort((a, b) => {
      if (a.type !== b.type) {
        return a.type === "directory" ? -1 : 1;
      }
      return a.name.localeCompare(b.name);
    });
  } catch (err) {
    console.error(`Failed to read directory tree for ${normDirPath}:`, err);
    return [];
  }
}

interface FlatFileItem {
  name: string;
  path: string;
  relativePath: string;
}

function getFlatFileList(dirPath: string, rootDir: string, list: FlatFileItem[] = [], maxFiles = 1500): FlatFileItem[] {
  const normDirPath = dirPath.replace(/\\/g, "/");
  const normRootDir = rootDir.replace(/\\/g, "/");
  if (list.length >= maxFiles) return list;
  try {
    const items = fs.readdirSync(normDirPath, { withFileTypes: true });
    for (const item of items) {
      if (list.length >= maxFiles) break;

      // Skip hidden folders and build folders
      if (
        item.name.startsWith(".") ||
        item.name === "node_modules" ||
        item.name === "out" ||
        item.name === ".next" ||
        item.name === "dist"
      ) {
        continue;
      }

      const itemPath = path.join(normDirPath, item.name).replace(/\\/g, "/");
      if (item.isDirectory()) {
        getFlatFileList(itemPath, normRootDir, list, maxFiles);
      } else {
        const relativePath = path.relative(normRootDir, itemPath).replace(/\\/g, "/");
        list.push({
          name: item.name,
          path: itemPath,
          relativePath: relativePath,
        });
      }
    }
  } catch (err) {
    console.error(`Failed to read flat file list for ${normDirPath}:`, err);
  }
  return list;
}

export async function GET(request: Request) {
  try {
    const { searchParams } = new URL(request.url);
    const action = searchParams.get("action");

    if (action === "list") {
      const rootPath = searchParams.get("root");
      const scopedStr = searchParams.get("scoped");
      
      const targetRoot = ((rootPath && fs.existsSync(rootPath)) ? rootPath : process.cwd()).replace(/\\/g, "/");
      const workspaceTree = getDirectoryTree(targetRoot);
      const scopedTrees: { name: string; path: string; tree: TreeNode[] }[] = [];

      if (scopedStr) {
        const scopedPaths = scopedStr.split(",");
        for (const p of scopedPaths) {
          const trimmed = p.trim().replace(/\\/g, "/");
          if (trimmed && fs.existsSync(trimmed)) {
            scopedTrees.push({
              name: path.basename(trimmed),
              path: trimmed,
              tree: getDirectoryTree(trimmed),
            });
          }
        }
      }

      return NextResponse.json({
        success: true,
        workspace: {
          name: path.basename(targetRoot) || "Workspace",
          path: targetRoot,
          tree: workspaceTree,
        },
        scoped: scopedTrees,
      });
    }

    if (action === "flat_list") {
      const rootPath = searchParams.get("root");
      const scopedStr = searchParams.get("scoped");
      
      const targetRoot = ((rootPath && fs.existsSync(rootPath)) ? rootPath : process.cwd()).replace(/\\/g, "/");
      const files: FlatFileItem[] = [];
      
      getFlatFileList(targetRoot, targetRoot, files);

      if (scopedStr) {
        const scopedPaths = scopedStr.split(",");
        for (const p of scopedPaths) {
          const trimmed = p.trim().replace(/\\/g, "/");
          if (trimmed && fs.existsSync(trimmed)) {
            getFlatFileList(trimmed, path.dirname(trimmed).replace(/\\/g, "/"), files);
          }
        }
      }

      return NextResponse.json({
        success: true,
        files: files,
      });
    }

    if (action === "browse_dirs") {
      const targetPathRaw = searchParams.get("path");
      const defaultDir = (process.env.ORIGINAL_CWD || process.cwd() || os.homedir()).replace(/\\/g, "/");
      let targetPath = (targetPathRaw && targetPathRaw.trim()) ? path.resolve(targetPathRaw) : defaultDir;
      targetPath = targetPath.replace(/\\/g, "/");

      if (!fs.existsSync(targetPath)) {
        return NextResponse.json({ error: "Directory does not exist" }, { status: 404 });
      }

      const stat = fs.statSync(targetPath);
      if (!stat.isDirectory()) {
        return NextResponse.json({ error: "Path is not a directory" }, { status: 400 });
      }

      const items = fs.readdirSync(targetPath, { withFileTypes: true });
      const directories: { name: string; path: string }[] = [];

      for (const item of items) {
        if (item.isDirectory()) {
          // Skip hidden directories
          if (item.name.startsWith(".")) continue;
          directories.push({
            name: item.name,
            path: path.join(targetPath, item.name).replace(/\\/g, "/"),
          });
        }
      }

      // Sort alphabetically
      directories.sort((a, b) => a.name.localeCompare(b.name));

      const parentPath = path.dirname(targetPath).replace(/\\/g, "/");
      const isRoot = parentPath === targetPath;

      return NextResponse.json({
        success: true,
        currentPath: targetPath,
        parentPath: isRoot ? null : parentPath,
        directories,
      });
    }

    if (action === "read") {
      const filePathRaw = searchParams.get("path");
      if (!filePathRaw) {
        return NextResponse.json({ error: "Missing required parameter 'path'" }, { status: 400 });
      }

      const filePath = filePathRaw.replace(/\\/g, "/");
      if (!fs.existsSync(filePath)) {
        return NextResponse.json({ error: "File does not exist" }, { status: 404 });
      }

      const content = fs.readFileSync(filePath, "utf8");
      return NextResponse.json({ success: true, content });
    }

    return NextResponse.json({ error: "Invalid action. Must be 'list', 'flat_list' or 'read'" }, { status: 400 });
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : "Unknown error";
    return NextResponse.json({ error: errorMessage }, { status: 500 });
  }
}

export async function POST(request: Request) {
  try {
    const body = await request.json();
    const { action, path: rawPath, content, type, oldPath: rawOldPath, newPath: rawNewPath } = body;
    const filePath = rawPath ? rawPath.replace(/\\/g, "/") : undefined;
    const oldPath = rawOldPath ? rawOldPath.replace(/\\/g, "/") : undefined;
    const newPath = rawNewPath ? rawNewPath.replace(/\\/g, "/") : undefined;

    if (action === "write") {
      if (!filePath || content === undefined) {
        return NextResponse.json({ error: "Missing 'path' or 'content' in body" }, { status: 400 });
      }

      // Ensure target directory exists
      const parentDir = path.dirname(filePath).replace(/\\/g, "/");
      if (!fs.existsSync(parentDir)) {
        fs.mkdirSync(parentDir, { recursive: true });
      }

      fs.writeFileSync(filePath, content, "utf8");
      return NextResponse.json({ success: true, message: "File saved successfully" });
    }

    if (action === "create") {
      if (!filePath || !type) {
        return NextResponse.json({ error: "Missing 'path' or 'type' in request body" }, { status: 400 });
      }

      if (fs.existsSync(filePath)) {
        return NextResponse.json({ error: "Path already exists" }, { status: 400 });
      }

      if (type === "directory") {
        fs.mkdirSync(filePath, { recursive: true });
        return NextResponse.json({ success: true, message: "Directory created successfully" });
      } else {
        const parentDir = path.dirname(filePath).replace(/\\/g, "/");
        if (!fs.existsSync(parentDir)) {
          fs.mkdirSync(parentDir, { recursive: true });
        }
        fs.writeFileSync(filePath, "", "utf8");
        return NextResponse.json({ success: true, message: "File created successfully" });
      }
    }

    if (action === "rename") {
      if (!oldPath || !newPath) {
        return NextResponse.json({ error: "Missing 'oldPath' or 'newPath' in request body" }, { status: 400 });
      }

      if (!fs.existsSync(oldPath)) {
        return NextResponse.json({ error: "Source path does not exist" }, { status: 404 });
      }

      if (fs.existsSync(newPath)) {
        return NextResponse.json({ error: "Target path already exists" }, { status: 400 });
      }

      const parentDir = path.dirname(newPath).replace(/\\/g, "/");
      if (!fs.existsSync(parentDir)) {
        fs.mkdirSync(parentDir, { recursive: true });
      }

      fs.renameSync(oldPath, newPath);
      return NextResponse.json({ success: true, message: "Renamed successfully" });
    }

    if (action === "delete") {
      if (!filePath) {
        return NextResponse.json({ error: "Missing 'path' in request body" }, { status: 400 });
      }

      if (!fs.existsSync(filePath)) {
        return NextResponse.json({ error: "Path does not exist" }, { status: 404 });
      }

      fs.rmSync(filePath, { recursive: true, force: true });
      return NextResponse.json({ success: true, message: "Deleted successfully" });
    }

    return NextResponse.json({ error: "Invalid action." }, { status: 400 });
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : "Unknown error";
    return NextResponse.json({ error: errorMessage }, { status: 500 });
  }
}
