import type { ExtensionAPI } from "@jaeswift/jae-coding-agent";
import { existsSync, writeFileSync, mkdirSync, readFileSync, readdirSync } from "node:fs";
import { join } from "node:path";
import { Type } from "@sinclair/typebox";

const SKILLS_API = "https://skills.jaeswift.xyz/api/skills";

interface SkillInfo {
  name: string;
  description: string;
  version: string;
  author: string;
}

export default function (pi: ExtensionAPI) {
  async function fetchJSON(url: string): Promise<any> {
    const result = await pi.exec("curl", ["-s", "-f", url]);
    if (result.code !== 0) {
      throw new Error(`HTTP request failed: ${result.stderr}`);
    }
    return JSON.parse(result.stdout);
  }

  function getSkillsDir(ctx: any): string {
    const dir = join(ctx.agentDir, "skills");
    if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
    return dir;
  }

  function listLocalSkills(ctx: any): string[] {
    const dir = getSkillsDir(ctx);
    try {
      return readdirSync(dir).filter((f) => f.endsWith(".md") || existsSync(join(dir, f, "SKILL.md")));
    } catch {
      return [];
    }
  }

  // /search-skills command
  pi.registerCommand("search-skills", {
    description: "Search the JAE skill marketplace: /search-skills <query>",
    handler: async (args, ctx) => {
      const query = args.trim();
      if (!query) {
        ctx.ui.notify("Usage: /search-skills <query>", "warning");
        return;
      }

      ctx.ui.notify(`\u{1F50D} Searching skills for: ${query}...`, "info");

      try {
        const skills = await fetchJSON(`${SKILLS_API}/search?q=${encodeURIComponent(query)}`);
        if (!skills || skills.length === 0) {
          ctx.ui.notify(`No skills found matching '${query}'.`, "info");
          return;
        }
        const list = skills
          .map((s: SkillInfo) => `  - ${s.name} (v${s.version}) by ${s.author}\n    ${s.description}`)
          .join("\n");
        ctx.ui.notify(`\u{1F3EA} Skills matching '${query}':\n${list}`, "info");
      } catch (err: any) {
        ctx.ui.notify(`Failed to search skills: ${err.message}\nAPI: ${SKILLS_API}`, "error");
      }
    },
  });

  // /install-skill command
  pi.registerCommand("install-skill", {
    description: "Install a skill from the marketplace: /install-skill <name>",
    handler: async (args, ctx) => {
      const name = args.trim();
      if (!name) {
        ctx.ui.notify("Usage: /install-skill <name>", "warning");
        return;
      }

      ctx.ui.notify(`\u{1F4E6} Installing skill: ${name}...`, "info");

      try {
        const skill = await fetchJSON(`${SKILLS_API}/${encodeURIComponent(name)}`);
        if (!skill || !skill.content) {
          ctx.ui.notify(`Skill '${name}' not found or has no content.`, "error");
          return;
        }

        const skillsDir = getSkillsDir(ctx);
        const skillDir = join(skillsDir, name);
        if (!existsSync(skillDir)) mkdirSync(skillDir, { recursive: true });

        writeFileSync(join(skillDir, "SKILL.md"), skill.content, "utf-8");

        // Write any additional files
        if (skill.files && typeof skill.files === "object") {
          for (const [filename, content] of Object.entries(skill.files)) {
            writeFileSync(join(skillDir, filename), content as string, "utf-8");
          }
        }

        ctx.ui.notify(
          `\u2705 Skill '${name}' installed to ${skillDir}\nRestart JAE to activate.`,
          "info",
        );
      } catch (err: any) {
        ctx.ui.notify(`Failed to install skill: ${err.message}`, "error");
      }
    },
  });

  // /publish-skill command
  pi.registerCommand("publish-skill", {
    description: "Publish a local skill to the marketplace: /publish-skill <name>",
    handler: async (args, ctx) => {
      const name = args.trim();
      if (!name) {
        ctx.ui.notify("Usage: /publish-skill <skill-dir-name>", "warning");
        return;
      }

      const skillsDir = getSkillsDir(ctx);
      const skillDir = join(skillsDir, name);
      const skillMd = join(skillDir, "SKILL.md");

      if (!existsSync(skillMd)) {
        ctx.ui.notify(`Skill '${name}' not found locally at ${skillDir}`, "error");
        return;
      }

      const content = readFileSync(skillMd, "utf-8");

      // Collect extra files
      const files: Record<string, string> = {};
      try {
        for (const f of readdirSync(skillDir)) {
          if (f !== "SKILL.md") {
            files[f] = readFileSync(join(skillDir, f), "utf-8");
          }
        }
      } catch { /* ignore */ }

      ctx.ui.notify(`\u{1F4E4} Publishing skill: ${name}...`, "info");

      try {
        const payload = JSON.stringify({ name, content, files });
        const result = await pi.exec(
          "curl",
          ["-s", "-f", "-X", "POST", "-H", "Content-Type: application/json", "-d", payload, SKILLS_API],
        );
        if (result.code === 0) {
          ctx.ui.notify(`\u2705 Skill '${name}' published to marketplace!`, "info");
        } else {
          ctx.ui.notify(`Publish failed: ${result.stderr}`, "error");
        }
      } catch (err: any) {
        ctx.ui.notify(`Publish error: ${err.message}`, "error");
      }
    },
  });

  // /skills command - list local skills
  pi.registerCommand("skills", {
    description: "List locally installed skills",
    handler: async (_args, ctx) => {
      const local = listLocalSkills(ctx);
      if (local.length === 0) {
        ctx.ui.notify("No skills installed. Use /search-skills and /install-skill to get started.", "info");
        return;
      }
      ctx.ui.notify(`\u{1F9E0} Installed Skills (${local.length}):\n${local.map((s) => `  - ${s}`).join("\n")}`, "info");
    },
  });

  // LLM tool for skill search
  pi.registerTool({
    name: "search_skills",
    label: "Search Skills",
    description: "Search the JAE skill marketplace for installable skills",
    parameters: Type.Object({
      query: Type.String({ description: "Search query for skills" }),
    }),
    execute: async (args, _ctx) => {
      try {
        const skills = await fetchJSON(`${SKILLS_API}/search?q=${encodeURIComponent(args.query)}`);
        return { output: JSON.stringify(skills, null, 2) };
      } catch (err: any) {
        return { error: `Skill search failed: ${err.message}` };
      }
    },
  });
}
