#!/usr/bin/env node

// src/registry.ts
import fs2 from "fs";
import path2 from "path";

// src/config.ts
import fs from "fs";
import path from "path";
import os from "os";
var MODES = [
  "elevator",
  "typewriter",
  "ambient",
  "retro",
  "minimal",
  "spotify"
];
var DEFAULT_CONFIG = {
  mode: "elevator",
  volume: 70,
  enabled: true
};
function getConfigDir() {
  if (process.env.CODEVATOR_HOME) return process.env.CODEVATOR_HOME;
  return path.join(os.homedir(), ".codevator");
}
function getConfigPath() {
  return path.join(getConfigDir(), "config.json");
}
function getConfig() {
  try {
    const raw = fs.readFileSync(getConfigPath(), "utf-8");
    return JSON.parse(raw);
  } catch {
    return { ...DEFAULT_CONFIG };
  }
}
function setConfig(partial) {
  const current = getConfig();
  const merged = { ...current, ...partial };
  const dir = getConfigDir();
  fs.mkdirSync(dir, { recursive: true });
  fs.writeFileSync(getConfigPath(), JSON.stringify(merged, null, 2));
}
function isValidMode(mode) {
  if (MODES.includes(mode)) return true;
  const soundFile = path.join(getConfigDir(), "sounds", `${mode}.mp3`);
  return fs.existsSync(soundFile);
}

// src/registry.ts
var REGISTRY_URL = "https://codevator.dev/sounds.json";
var FETCH_TIMEOUT_MS = 15e3;
function fetchWithTimeout(url) {
  const controller = new AbortController();
  const id = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
  return fetch(url, { signal: controller.signal }).finally(() => clearTimeout(id));
}
function isValidManifest(m) {
  return typeof m === "object" && m !== null && typeof m.baseUrl === "string" && m.baseUrl.length > 0 && Array.isArray(m.sounds);
}
function getSoundsDir() {
  return path2.join(getConfigDir(), "sounds");
}
function getManifestCache() {
  return path2.join(getConfigDir(), "sounds.json");
}
async function fetchManifest() {
  try {
    const res = await fetchWithTimeout(REGISTRY_URL);
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    const raw = await res.json();
    if (!isValidManifest(raw)) throw new Error("Invalid manifest format");
    const manifest = raw;
    const dir = getConfigDir();
    fs2.mkdirSync(dir, { recursive: true });
    fs2.writeFileSync(getManifestCache(), JSON.stringify(manifest, null, 2));
    return manifest;
  } catch {
    try {
      const cached = JSON.parse(fs2.readFileSync(getManifestCache(), "utf-8"));
      if (!isValidManifest(cached)) throw new Error("Invalid cached manifest");
      return cached;
    } catch {
      throw new Error("Could not fetch sound registry and no local cache found");
    }
  }
}
function getCachedManifest() {
  try {
    const raw = JSON.parse(fs2.readFileSync(getManifestCache(), "utf-8"));
    return isValidManifest(raw) ? raw : null;
  } catch {
    return null;
  }
}
async function downloadFile(baseUrl, filename, soundsDir) {
  const dest = path2.join(soundsDir, `${filename}.mp3`);
  if (!dest.startsWith(soundsDir + path2.sep)) throw new Error("Invalid sound name");
  if (fs2.existsSync(dest)) return dest;
  const url = `${baseUrl}/${filename}.mp3`;
  const res = await fetchWithTimeout(url);
  if (!res.ok) throw new Error(`Failed to download: HTTP ${res.status}`);
  fs2.writeFileSync(dest, Buffer.from(await res.arrayBuffer()));
  return dest;
}
async function downloadSound(name, manifest) {
  const m = manifest ?? await fetchManifest();
  const entry = m.sounds.find((s) => s.name === name);
  if (!entry) throw new Error(`Sound '${name}' not found in registry`);
  const soundsDir = getSoundsDir();
  fs2.mkdirSync(soundsDir, { recursive: true });
  const dest = await downloadFile(m.baseUrl, name, soundsDir);
  const fileCount = entry.files ?? 1;
  if (fileCount > 1) {
    await Promise.all(
      Array.from(
        { length: fileCount - 1 },
        (_, i) => downloadFile(m.baseUrl, `${name}-${i + 2}`, soundsDir).catch(() => {
        })
      )
    );
  }
  return dest;
}
function isInstalled(name) {
  const soundsDir = getSoundsDir();
  const filePath = path2.join(soundsDir, `${name}.mp3`);
  if (!filePath.startsWith(soundsDir + path2.sep)) return false;
  return fs2.existsSync(filePath);
}
function listInstalled() {
  const dir = getSoundsDir();
  try {
    return fs2.readdirSync(dir).filter((f) => f.endsWith(".mp3") && !/^.+-\d+\.mp3$/.test(f)).map((f) => f.replace(/\.mp3$/, ""));
  } catch {
    return [];
  }
}

export {
  MODES,
  getConfigDir,
  getConfig,
  setConfig,
  isValidMode,
  fetchManifest,
  getCachedManifest,
  downloadSound,
  isInstalled,
  listInstalled
};
