import { readFile } from "node:fs/promises";
import { join } from "node:path";
import { parseHooksConfig } from "../../hooks/config/parseHooksConfig.js";
import type { PilotDeckPluginManifest } from "../protocol/manifest.js";
import type { PilotDeckLoadedPlugin, PilotDeckPluginSourceKind } from "../protocol/plugin.js";
import { parsePluginManifest } from "../config/parsePluginManifest.js";
import { loadPluginCommands } from "./PluginCommandLoader.js";

/**
 * Loads a standalone skill directory (containing SKILL.md) as a pseudo-plugin.
 * No plugin.json required — mirrors the legacy standalone skill directory layout.
 */
export async function loadSkillFromPath(
  skillDir: string,
  source: PilotDeckPluginSourceKind,
): Promise<PilotDeckLoadedPlugin> {
  const name = skillDir.split(/[\\/]/u).at(-1) ?? "skill";
  const skills = await loadPluginCommands({ pluginName: name, baseDir: skillDir });
  return {
    name,
    path: skillDir,
    source,
    manifest: { name, version: "0.0.0" },
    skills,
  };
}

export async function loadPluginFromPath(
  pluginPath: string,
  source: PilotDeckPluginSourceKind,
): Promise<PilotDeckLoadedPlugin> {
  const manifestPath = join(pluginPath, "plugin.json");
  const manifest = parsePluginManifest(JSON.parse(await readFile(manifestPath, "utf8")) as unknown);
  const hooksConfig = await loadHooksConfig(pluginPath, manifest);
  const commands = await loadConfiguredMarkdown(pluginPath, manifest.commands, "commands");
  const skills = await loadConfiguredMarkdown(pluginPath, manifest.skills, "skills");
  const outputStyles = await loadConfiguredMarkdown(pluginPath, manifest.outputStyles, "output-styles");

  return {
    name: manifest.name,
    path: pluginPath,
    source,
    manifest,
    hooksConfig,
    commands,
    skills,
    outputStyles,
    mcpServers: manifest.mcpServers,
    lspServers: manifest.lspServers,
  };
}

async function loadHooksConfig(pluginPath: string, manifest: PilotDeckPluginManifest) {
  if (typeof manifest.hooks === "object" && manifest.hooks !== null) {
    return parseHooksConfig(manifest.hooks).settings;
  }
  const hookPath = typeof manifest.hooks === "string" ? manifest.hooks : "hooks/hooks.json";
  try {
    const raw = JSON.parse(await readFile(join(pluginPath, hookPath), "utf8")) as unknown;
    return parseHooksConfig(raw).settings;
  } catch {
    return undefined;
  }
}

async function loadConfiguredMarkdown(
  pluginPath: string,
  configured: string | string[] | undefined,
  fallbackDir: "commands" | "skills" | "output-styles",
) {
  const dirs = configured === undefined ? [fallbackDir] : Array.isArray(configured) ? configured : [configured];
  const loaded = await Promise.all(
    dirs.map((dir) => loadPluginCommands({ pluginName: "", baseDir: join(pluginPath, dir) }).catch(() => [])),
  );
  const pluginName = pluginPath.split(/[\\/]/u).at(-1) ?? "";
  return loaded.flat().map((command) => ({
    ...command,
    name: command.name.startsWith(":")
      ? `${pluginName}${command.name}`
      : command.name.replace(/^:/u, `${pluginName}:`),
  }));
}