import type { Resource } from "@modelcontextprotocol/sdk/types.js";
import { loadManifest } from "@mandujs/core";
import { getTransactionStatus } from "@mandujs/core/change";
import type { GeneratedMap } from "@mandujs/core/generator";
import { getWatcher } from "@mandujs/core/watcher";
import { getProjectPaths, readJsonFile } from "../utils/project.js";
import {
  getGuide,
  listGuides,
  getRecipe,
  listRecipes,
  listSkills,
  getSkill,
  listSkillRules,
  getSkillRule,
} from "./skills/index.js";
import path from "path";

export const resourceDefinitions: Resource[] = [
  {
    uri: "mandu://spec/manifest",
    name: "Routes Manifest",
    description: "Current routes.manifest.json content",
    mimeType: "application/json",
  },
  {
    uri: "mandu://generated/map",
    name: "Generated Map",
    description: "Map of generated files to their source routes",
    mimeType: "application/json",
  },
  {
    uri: "mandu://transaction/active",
    name: "Active Transaction",
    description: "Current active transaction information",
    mimeType: "application/json",
  },
  {
    uri: "mandu://slots/{routeId}",
    name: "Route Slot",
    description: "Slot file content for a specific route",
    mimeType: "text/typescript",
  },
  {
    uri: "mandu://watch/warnings",
    name: "Watch Warnings",
    description: "Recent file watcher warnings (architecture rule violations)",
    mimeType: "application/json",
  },
  {
    uri: "mandu://watch/status",
    name: "Watch Status",
    description: "File watcher status (active/inactive, uptime, rule count)",
    mimeType: "application/json",
  },
  // Skills - Guides
  {
    uri: "mandu://skills/guides",
    name: "Skills Guide List",
    description: "Available guide documents for learning Mandu",
    mimeType: "application/json",
  },
  {
    uri: "mandu://skills/guides/slot",
    name: "Slot Guide",
    description: "Guide for writing business logic with Mandu.filling() API",
    mimeType: "text/markdown",
  },
  {
    uri: "mandu://skills/guides/fs-routes",
    name: "FS Routes Guide",
    description: "Guide for file-system based routing patterns",
    mimeType: "text/markdown",
  },
  {
    uri: "mandu://skills/guides/hydration",
    name: "Hydration Guide",
    description: "Guide for Island hydration and client components",
    mimeType: "text/markdown",
  },
  {
    uri: "mandu://skills/guides/guard",
    name: "Guard Guide",
    description: "Guide for architecture enforcement and layer dependencies",
    mimeType: "text/markdown",
  },
  // Skills - Recipes
  {
    uri: "mandu://skills/recipes",
    name: "Skills Recipe List",
    description: "Step-by-step recipes for common tasks",
    mimeType: "application/json",
  },
  {
    uri: "mandu://skills/recipes/add-api-route",
    name: "Add API Route Recipe",
    description: "Step-by-step guide to add a new REST API endpoint",
    mimeType: "text/markdown",
  },
  {
    uri: "mandu://skills/recipes/add-page",
    name: "Add Page Recipe",
    description: "Step-by-step guide to add a new page",
    mimeType: "text/markdown",
  },
  {
    uri: "mandu://skills/recipes/add-auth",
    name: "Add Auth Recipe",
    description: "Step-by-step guide to add authentication",
    mimeType: "text/markdown",
  },
  {
    uri: "mandu://skills/recipes/add-island",
    name: "Add Island Recipe",
    description: "Step-by-step guide to add an interactive Island component",
    mimeType: "text/markdown",
  },
  {
    uri: "mandu://skills/recipes/add-database",
    name: "Add Database Recipe",
    description: "Step-by-step guide to connect a database",
    mimeType: "text/markdown",
  },
  // Agent Skills (file-based)
  {
    uri: "mandu://skills",
    name: "Available Skills",
    description: "List of all Agent Skills for learning Mandu patterns",
    mimeType: "application/json",
  },
  {
    uri: "mandu://skills/{skillId}",
    name: "Skill Overview",
    description: "SKILL.md content with overview and rule categories",
    mimeType: "text/markdown",
  },
  {
    uri: "mandu://skills/{skillId}/rules",
    name: "Skill Rules",
    description: "List of rules for a specific skill",
    mimeType: "application/json",
  },
  {
    uri: "mandu://skills/{skillId}/rules/{ruleId}",
    name: "Skill Rule",
    description: "Detailed rule documentation",
    mimeType: "text/markdown",
  },
];

type ResourceHandler = (params: Record<string, string>) => Promise<unknown>;

export function resourceHandlers(
  projectRoot: string
): Record<string, ResourceHandler> {
  const paths = getProjectPaths(projectRoot);

  return {
    "mandu://spec/manifest": async () => {
      const result = await loadManifest(paths.manifestPath);
      if (!result.success || !result.data) {
        return {
          error: "Failed to load manifest",
          details: result.errors,
        };
      }

      return {
        version: result.data.version,
        routeCount: result.data.routes.length,
        routes: result.data.routes,
      };
    },

    "mandu://generated/map": async () => {
      const generatedMap = await readJsonFile<GeneratedMap>(paths.generatedMapPath);
      if (!generatedMap) {
        return {
          exists: false,
          message: "generated.map.json not found. Run mandu generate first.",
        };
      }

      return {
        exists: true,
        version: generatedMap.version,
        generatedAt: generatedMap.generatedAt,
        specSource: generatedMap.specSource,
        fileCount: Object.keys(generatedMap.files).length,
        files: generatedMap.files,
        frameworkPaths: generatedMap.frameworkPaths,
      };
    },

    "mandu://transaction/active": async () => {
      const { state, change } = await getTransactionStatus(projectRoot);

      if (!state.active) {
        return {
          hasActive: false,
          message: "No active transaction",
        };
      }

      return {
        hasActive: true,
        changeId: state.changeId,
        snapshotId: state.snapshotId,
        change: change
          ? {
              id: change.id,
              message: change.message,
              status: change.status,
              createdAt: change.createdAt,
              autoGenerated: change.autoGenerated,
            }
          : null,
      };
    },

    "mandu://slots/{routeId}": async (params: Record<string, string>) => {
      const { routeId } = params;

      if (!routeId) {
        return { error: "routeId parameter is required" };
      }

      // Load manifest to find the route
      const result = await loadManifest(paths.manifestPath);
      if (!result.success || !result.data) {
        return { error: result.errors };
      }

      const route = result.data.routes.find((r) => r.id === routeId);
      if (!route) {
        return { error: `Route not found: ${routeId}` };
      }

      if (!route.slotModule) {
        return {
          error: `Route '${routeId}' does not have a slotModule`,
        };
      }

      const slotPath = path.join(projectRoot, route.slotModule);
      const file = Bun.file(slotPath);

      if (!(await file.exists())) {
        return {
          exists: false,
          slotModule: route.slotModule,
          message: "Slot file does not exist",
        };
      }

      const content = await file.text();
      return {
        exists: true,
        slotModule: route.slotModule,
        routeId,
        kind: route.kind,
        pattern: route.pattern,
        content,
      };
    },

    "mandu://watch/warnings": async () => {
      const watcher = getWatcher();
      if (!watcher) {
        return { active: false, warnings: [] };
      }

      const warnings = watcher.getRecentWarnings(50);
      return {
        active: true,
        count: warnings.length,
        warnings: warnings.map((w) => ({
          ruleId: w.ruleId,
          file: w.file,
          message: w.message,
          event: w.event,
          timestamp: w.timestamp.toISOString(),
        })),
      };
    },

    "mandu://watch/status": async () => {
      const watcher = getWatcher();
      if (!watcher) {
        return { active: false };
      }

      const status = watcher.getStatus();
      return {
        active: status.active,
        rootDir: status.rootDir,
        fileCount: status.fileCount,
        warningCount: status.recentWarnings.length,
        uptime: status.startedAt
          ? Math.floor((Date.now() - status.startedAt.getTime()) / 1000)
          : 0,
        startedAt: status.startedAt?.toISOString() || null,
      };
    },

    // Skills - Guides
    "mandu://skills/guides": async () => {
      return {
        guides: listGuides(),
        usage: "Read a specific guide with mandu://skills/guides/{id}",
      };
    },

    "mandu://skills/guides/slot": async () => {
      const content = getGuide("slot");
      return { id: "slot", content };
    },

    "mandu://skills/guides/fs-routes": async () => {
      const content = getGuide("fs-routes");
      return { id: "fs-routes", content };
    },

    "mandu://skills/guides/hydration": async () => {
      const content = getGuide("hydration");
      return { id: "hydration", content };
    },

    "mandu://skills/guides/guard": async () => {
      const content = getGuide("guard");
      return { id: "guard", content };
    },

    // Skills - Recipes
    "mandu://skills/recipes": async () => {
      return {
        recipes: listRecipes(),
        usage: "Read a specific recipe with mandu://skills/recipes/{id}",
      };
    },

    "mandu://skills/recipes/add-api-route": async () => {
      const content = getRecipe("add-api-route");
      return { id: "add-api-route", content };
    },

    "mandu://skills/recipes/add-page": async () => {
      const content = getRecipe("add-page");
      return { id: "add-page", content };
    },

    "mandu://skills/recipes/add-auth": async () => {
      const content = getRecipe("add-auth");
      return { id: "add-auth", content };
    },

    "mandu://skills/recipes/add-island": async () => {
      const content = getRecipe("add-island");
      return { id: "add-island", content };
    },

    "mandu://skills/recipes/add-database": async () => {
      const content = getRecipe("add-database");
      return { id: "add-database", content };
    },

    // Agent Skills (file-based)
    "mandu://skills": async () => {
      return {
        skills: listSkills(),
        usage: {
          overview: "Read skill overview with mandu://skills/{skillId}",
          rules: "List rules with mandu://skills/{skillId}/rules",
          rule: "Read specific rule with mandu://skills/{skillId}/rules/{ruleId}",
        },
        availableSkills: [
          "mandu-slot",
          "mandu-fs-routes",
          "mandu-hydration",
          "mandu-guard",
        ],
      };
    },

    "mandu://skills/{skillId}": async (params: Record<string, string>) => {
      const { skillId } = params;
      if (!skillId) {
        return { error: "skillId parameter is required" };
      }

      const skill = await getSkill(skillId);
      if (!skill) {
        return { error: `Skill not found: ${skillId}` };
      }

      const rules = await listSkillRules(skillId);

      return {
        id: skillId,
        meta: skill.meta,
        content: skill.content,
        rulesCount: rules.length,
        rulesUri: `mandu://skills/${skillId}/rules`,
      };
    },

    "mandu://skills/{skillId}/rules": async (params: Record<string, string>) => {
      const { skillId } = params;
      if (!skillId) {
        return { error: "skillId parameter is required" };
      }

      const rules = await listSkillRules(skillId);
      if (rules.length === 0) {
        return { error: `No rules found for skill: ${skillId}` };
      }

      return {
        skillId,
        count: rules.length,
        rules: rules.map((r) => ({
          ...r,
          uri: `mandu://skills/${skillId}/rules/${r.id}`,
        })),
      };
    },

    "mandu://skills/{skillId}/rules/{ruleId}": async (params: Record<string, string>) => {
      const { skillId, ruleId } = params;
      if (!skillId || !ruleId) {
        return { error: "skillId and ruleId parameters are required" };
      }

      const rule = await getSkillRule(skillId, ruleId);
      if (!rule) {
        return { error: `Rule not found: ${skillId}/${ruleId}` };
      }

      return {
        skillId,
        ruleId,
        meta: rule.meta,
        content: rule.content,
      };
    },
  };
}
