#!/usr/bin/env node
import { createHash } from "node:crypto";
import { existsSync, statSync } from "node:fs";
import { mkdir, readFile, realpath, rename, writeFile } from "node:fs/promises";
import { homedir } from "node:os";
import { basename, dirname, resolve } from "node:path";
const DEFAULT_REGISTRY_PATH = resolve(homedir(), ".boring-ui", "workspaces.yaml");
function getDefaultLocalWorkspaceRegistryPath() {
  return process.env.BORING_UI_WORKSPACES_PATH ? resolve(process.env.BORING_UI_WORKSPACES_PATH) : DEFAULT_REGISTRY_PATH;
}
function slugify(value) {
  return value.trim().toLowerCase().normalize("NFKD").replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "") || "workspace";
}
function workspaceIdForPath(path) {
  const hash = createHash("sha1").update(path).digest("hex").slice(0, 8);
  return `${slugify(basename(path))}-${hash}`;
}
function yamlString(value) {
  if (/^[a-zA-Z0-9_./:@ -]+$/.test(value) && !value.startsWith(" ") && !value.endsWith(" ")) {
    return value;
  }
  return JSON.stringify(value);
}
function unquoteYamlString(value) {
  const trimmed = value.trim();
  if (!trimmed) return "";
  if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
    try {
      return JSON.parse(trimmed);
    } catch {
      return trimmed.slice(1, -1);
    }
  }
  return trimmed;
}
function parseRegistryYaml(content) {
  const result = [];
  let current = null;
  for (const line of content.split(/\r?\n/)) {
    const trimmed = line.trim();
    if (!trimmed || trimmed.startsWith("#") || trimmed === "version: 1" || trimmed === "workspaces:") continue;
    const itemMatch = line.match(/^\s*-\s+id:\s*(.*)$/);
    if (itemMatch) {
      if (current?.id && current.name && current.path && current.createdAt && current.updatedAt) {
        result.push(current);
      }
      current = { id: unquoteYamlString(itemMatch[1] ?? "") };
      continue;
    }
    const fieldMatch = line.match(/^\s+(name|path|createdAt|updatedAt):\s*(.*)$/);
    if (fieldMatch && current) {
      current[fieldMatch[1]] = unquoteYamlString(fieldMatch[2] ?? "");
    }
  }
  if (current?.id && current.name && current.path && current.createdAt && current.updatedAt) {
    result.push(current);
  }
  return result;
}
function serializeRegistryYaml(workspaces) {
  const lines = ["version: 1", "workspaces:"];
  for (const workspace of workspaces) {
    lines.push(
      `  - id: ${yamlString(workspace.id)}`,
      `    name: ${yamlString(workspace.name)}`,
      `    path: ${yamlString(workspace.path)}`,
      `    createdAt: ${yamlString(workspace.createdAt)}`,
      `    updatedAt: ${yamlString(workspace.updatedAt)}`
    );
  }
  return `${lines.join("\n")}
`;
}
async function resolveWorkspacePath(input) {
  const absolute = resolve(input);
  try {
    return await realpath(absolute);
  } catch {
    return absolute;
  }
}
function pathIsDirectory(path) {
  try {
    return statSync(path).isDirectory();
  } catch {
    return false;
  }
}
function pathExists(path) {
  return existsSync(path);
}
function withAvailability(workspace) {
  return { ...workspace, available: pathIsDirectory(workspace.path) };
}
function createLocalWorkspaceRegistry(path = getDefaultLocalWorkspaceRegistryPath()) {
  async function readStored() {
    try {
      return parseRegistryYaml(await readFile(path, "utf-8"));
    } catch (error) {
      if (error?.code === "ENOENT") return [];
      throw error;
    }
  }
  async function writeStored(workspaces) {
    await mkdir(dirname(path), { recursive: true });
    const tmp = `${path}.${process.pid}.${Date.now()}.tmp`;
    await writeFile(tmp, serializeRegistryYaml(workspaces), "utf-8");
    await rename(tmp, path);
  }
  return {
    path,
    async list() {
      return (await readStored()).map(withAvailability);
    },
    async get(id) {
      const workspace = (await readStored()).find((entry) => entry.id === id);
      return workspace ? withAvailability(workspace) : null;
    },
    async add(inputPath, opts) {
      const workspacePath = await resolveWorkspacePath(inputPath);
      if (pathExists(workspacePath) && !pathIsDirectory(workspacePath)) {
        throw new Error(`workspace path is not a directory: ${workspacePath}`);
      }
      const now = (/* @__PURE__ */ new Date()).toISOString();
      const workspaces = await readStored();
      const id = workspaceIdForPath(workspacePath);
      const existing = workspaces.find((entry) => entry.id === id);
      if (existing) return withAvailability(existing);
      const workspace = {
        id,
        name: opts?.name?.trim() || basename(workspacePath) || id,
        path: workspacePath,
        createdAt: now,
        updatedAt: now
      };
      workspaces.push(workspace);
      await writeStored(workspaces);
      return withAvailability(workspace);
    },
    async remove(id) {
      await writeStored((await readStored()).filter((entry) => entry.id !== id));
    },
    async rename(id, name) {
      const nextName = name.trim();
      if (!nextName) throw new Error("workspace name is required");
      const workspaces = await readStored();
      const workspace = workspaces.find((entry) => entry.id === id);
      if (!workspace) throw new Error(`workspace not found: ${id}`);
      workspace.name = nextName;
      workspace.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
      await writeStored(workspaces);
      return withAvailability(workspace);
    }
  };
}
export {
  createLocalWorkspaceRegistry,
  getDefaultLocalWorkspaceRegistryPath
};
