const fs = require("fs");
const path = require("path");
const {
  listSkillIdsRecursive,
  readSkill,
  tokenize,
  unique,
} = require("../lib/skill-utils");

const ROOT = path.resolve(__dirname, "..");
const SKILLS_DIR = path.join(ROOT, ".agent", "skills");

const STOPWORDS = new Set([
  "a",
  "an",
  "and",
  "are",
  "as",
  "at",
  "be",
  "but",
  "by",
  "for",
  "from",
  "has",
  "have",
  "in",
  "into",
  "is",
  "it",
  "its",
  "of",
  "on",
  "or",
  "our",
  "out",
  "over",
  "that",
  "the",
  "their",
  "they",
  "this",
  "to",
  "use",
  "when",
  "with",
  "you",
  "your",
  "will",
  "can",
  "if",
  "not",
  "only",
  "also",
  "more",
  "best",
  "practice",
  "practices",
  "expert",
  "specialist",
  "focused",
  "focus",
  "master",
  "modern",
  "advanced",
  "comprehensive",
  "production",
  "production-ready",
  "ready",
  "build",
  "create",
  "deliver",
  "design",
  "implement",
  "implementation",
  "strategy",
  "strategies",
  "patterns",
  "pattern",
  "workflow",
  "workflows",
  "guide",
  "template",
  "templates",
  "tool",
  "tools",
  "project",
  "projects",
  "support",
  "manage",
  "management",
  "system",
  "systems",
  "services",
  "service",
  "across",
  "end",
  "end-to-end",
  "using",
  "based",
  "ensure",
  "ensure",
  "help",
  "needs",
  "need",
  "focuses",
  "handles",
  "builds",
  "make",
]);

const TAG_STOPWORDS = new Set([
  "pro",
  "expert",
  "patterns",
  "pattern",
  "workflow",
  "workflows",
  "templates",
  "template",
  "toolkit",
  "tools",
  "tool",
  "project",
  "projects",
  "guide",
  "management",
  "engineer",
  "architect",
  "developer",
  "specialist",
  "assistant",
  "analysis",
  "review",
  "reviewer",
  "automation",
  "orchestration",
  "scaffold",
  "scaffolding",
  "implementation",
  "strategy",
  "context",
  "management",
  "feature",
  "features",
  "smart",
  "system",
  "systems",
  "design",
  "development",
  "development",
  "test",
  "testing",
  "workflow",
]);

const CATEGORY_RULES = [
  {
    name: "security",
    keywords: [
      "security",
      "sast",
      "compliance",
      "privacy",
      "threat",
      "vulnerability",
      "owasp",
      "pci",
      "gdpr",
      "secrets",
      "risk",
      "malware",
      "forensics",
      "attack",
      "incident",
      "auth",
      "mtls",
      "zero",
      "trust",
    ],
  },
  {
    name: "infrastructure",
    keywords: [
      "kubernetes",
      "k8s",
      "helm",
      "terraform",
      "cloud",
      "network",
      "devops",
      "gitops",
      "prometheus",
      "grafana",
      "observability",
      "monitoring",
      "logging",
      "tracing",
      "deployment",
      "istio",
      "linkerd",
      "service",
      "mesh",
      "slo",
      "sre",
      "oncall",
      "incident",
      "pipeline",
      "cicd",
      "ci",
      "cd",
      "kafka",
    ],
  },
  {
    name: "data-ai",
    keywords: [
      "data",
      "database",
      "db",
      "sql",
      "postgres",
      "mysql",
      "analytics",
      "etl",
      "warehouse",
      "dbt",
      "ml",
      "ai",
      "llm",
      "rag",
      "vector",
      "embedding",
      "spark",
      "airflow",
      "cdc",
      "pipeline",
    ],
  },
  {
    name: "development",
    keywords: [
      "python",
      "javascript",
      "typescript",
      "java",
      "golang",
      "go",
      "rust",
      "csharp",
      "dotnet",
      "php",
      "ruby",
      "node",
      "react",
      "frontend",
      "backend",
      "mobile",
      "ios",
      "android",
      "flutter",
      "fastapi",
      "django",
      "nextjs",
      "vue",
      "api",
    ],
  },
  {
    name: "architecture",
    keywords: [
      "architecture",
      "c4",
      "microservices",
      "event",
      "cqrs",
      "saga",
      "domain",
      "ddd",
      "patterns",
      "decision",
      "adr",
    ],
  },
  {
    name: "testing",
    keywords: ["testing", "tdd", "unit", "e2e", "qa", "test"],
  },
  {
    name: "business",
    keywords: [
      "business",
      "market",
      "sales",
      "finance",
      "startup",
      "legal",
      "hr",
      "product",
      "customer",
      "seo",
      "marketing",
      "kpi",
      "contract",
      "employment",
    ],
  },
  {
    name: "workflow",
    keywords: [
      "workflow",
      "orchestration",
      "conductor",
      "automation",
      "process",
      "collaboration",
    ],
  },
];

const BUNDLE_RULES = {
  "core-dev": {
    description:
      "Core development skills across languages, frameworks, and backend/frontend fundamentals.",
    keywords: [
      "python",
      "javascript",
      "typescript",
      "go",
      "golang",
      "rust",
      "java",
      "node",
      "frontend",
      "backend",
      "react",
      "fastapi",
      "django",
      "nextjs",
      "api",
      "mobile",
      "ios",
      "android",
      "flutter",
      "php",
      "ruby",
    ],
  },
  "security-core": {
    description: "Security, privacy, and compliance essentials.",
    keywords: [
      "security",
      "sast",
      "compliance",
      "threat",
      "risk",
      "privacy",
      "secrets",
      "owasp",
      "gdpr",
      "pci",
      "vulnerability",
      "auth",
    ],
  },
  "k8s-core": {
    description: "Kubernetes and service mesh essentials.",
    keywords: [
      "kubernetes",
      "k8s",
      "helm",
      "istio",
      "linkerd",
      "service",
      "mesh",
    ],
  },
  "data-core": {
    description: "Data engineering and analytics foundations.",
    keywords: [
      "data",
      "database",
      "sql",
      "dbt",
      "airflow",
      "spark",
      "analytics",
      "etl",
      "warehouse",
      "postgres",
      "mysql",
      "kafka",
    ],
  },
  "ops-core": {
    description: "Operations, observability, and delivery pipelines.",
    keywords: [
      "observability",
      "monitoring",
      "logging",
      "tracing",
      "prometheus",
      "grafana",
      "devops",
      "gitops",
      "deployment",
      "cicd",
      "pipeline",
      "slo",
      "sre",
      "incident",
    ],
  },
};

const CURATED_COMMON = [
  "bash-pro",
  "python-pro",
  "javascript-pro",
  "typescript-pro",
  "golang-pro",
  "rust-pro",
  "java-pro",
  "frontend-developer",
  "backend-architect",
  "nodejs-backend-patterns",
  "fastapi-pro",
  "api-design-principles",
  "sql-pro",
  "database-architect",
  "kubernetes-architect",
  "terraform-specialist",
  "observability-engineer",
  "security-auditor",
  "sast-configuration",
  "gitops-workflow",
];

function normalizeTokens(tokens) {
  return unique(tokens.map((token) => token.toLowerCase())).filter(Boolean);
}

function deriveTags(skill) {
  let tags = Array.isArray(skill.tags) ? skill.tags : [];
  tags = tags.map((tag) => tag.toLowerCase()).filter(Boolean);

  if (!tags.length) {
    tags = skill.id
      .split("-")
      .map((tag) => tag.toLowerCase())
      .filter((tag) => tag && !TAG_STOPWORDS.has(tag));
  }

  return normalizeTokens(tags);
}

function detectCategory(skill, tags) {
  const haystack = normalizeTokens([
    ...tags,
    ...tokenize(skill.name),
    ...tokenize(skill.description),
  ]);
  const haystackSet = new Set(haystack);

  for (const rule of CATEGORY_RULES) {
    for (const keyword of rule.keywords) {
      if (haystackSet.has(keyword)) {
        return rule.name;
      }
    }
  }

  return "general";
}

function buildTriggers(skill, tags) {
  const tokens = tokenize(`${skill.name} ${skill.description}`).filter(
    (token) => token.length >= 2 && !STOPWORDS.has(token),
  );
  return unique([...tags, ...tokens]).slice(0, 12);
}

function buildAliases(skills) {
  const existingIds = new Set(skills.map((skill) => skill.id));
  const aliases = {};
  const used = new Set();

  for (const skill of skills) {
    if (skill.name && skill.name !== skill.id) {
      const alias = skill.name.toLowerCase();
      if (!existingIds.has(alias) && !used.has(alias)) {
        aliases[alias] = skill.id;
        used.add(alias);
      }
    }

    const tokens = skill.id.split("-").filter(Boolean);
    if (skill.id.length < 28 || tokens.length < 4) continue;

    const deduped = [];
    const tokenSeen = new Set();
    for (const token of tokens) {
      if (tokenSeen.has(token)) continue;
      tokenSeen.add(token);
      deduped.push(token);
    }

    const aliasTokens =
      deduped.length > 3
        ? [deduped[0], deduped[1], deduped[deduped.length - 1]]
        : deduped;
    const alias = unique(aliasTokens).join("-");

    if (!alias || alias === skill.id) continue;
    if (existingIds.has(alias) || used.has(alias)) continue;

    aliases[alias] = skill.id;
    used.add(alias);
  }

  return aliases;
}

function buildBundles(skills) {
  const bundles = {};
  const skillTokens = new Map();

  for (const skill of skills) {
    const tokens = normalizeTokens([
      ...skill.tags,
      ...tokenize(skill.name),
      ...tokenize(skill.description),
    ]);
    skillTokens.set(skill.id, new Set(tokens));
  }

  for (const [bundleName, rule] of Object.entries(BUNDLE_RULES)) {
    const bundleSkills = [];
    const keywords = rule.keywords.map((keyword) => keyword.toLowerCase());

    for (const skill of skills) {
      const tokenSet = skillTokens.get(skill.id) || new Set();
      if (keywords.some((keyword) => tokenSet.has(keyword))) {
        bundleSkills.push(skill.id);
      }
    }

    bundles[bundleName] = {
      description: rule.description,
      skills: bundleSkills.sort(),
    };
  }

  const common = CURATED_COMMON.filter((skillId) => skillTokens.has(skillId));

  return { bundles, common };
}

function truncate(value, limit) {
  if (!value || value.length <= limit) return value || "";
  return `${value.slice(0, limit - 3)}...`;
}

function renderCatalogMarkdown(catalog) {
  const lines = [];
  lines.push("# Skill Catalog");
  lines.push("");
  lines.push(`Generated at: ${catalog.generatedAt}`);
  lines.push("");
  lines.push(`Total skills: ${catalog.total}`);
  lines.push("");

  const categories = Array.from(
    new Set(catalog.skills.map((skill) => skill.category)),
  ).sort();
  for (const category of categories) {
    const grouped = catalog.skills.filter(
      (skill) => skill.category === category,
    );
    lines.push(`## ${category} (${grouped.length})`);
    lines.push("");
    lines.push("| Skill | Description | Tags | Triggers |");
    lines.push("| --- | --- | --- | --- |");

    for (const skill of grouped) {
      const description = truncate(skill.description, 160).replace(
        /\|/g,
        "\\|",
      );
      const tags = skill.tags.join(", ");
      const triggers = skill.triggers.join(", ");
      lines.push(
        `| \`${skill.id}\` | ${description} | ${tags} | ${triggers} |`,
      );
    }

    lines.push("");
  }

  return lines.join("\n");
}

function buildCatalog() {
  const skillRelPaths = listSkillIdsRecursive(SKILLS_DIR);
  const skills = skillRelPaths.map((relPath) => readSkill(SKILLS_DIR, relPath));
  const catalogSkills = [];

  for (const skill of skills) {
    const tags = deriveTags(skill);
    const category = detectCategory(skill, tags);
    const triggers = buildTriggers(skill, tags);

    catalogSkills.push({
      id: skill.id,
      name: skill.name,
      description: skill.description,
      category,
      tags,
      triggers,
      path: path.relative(ROOT, skill.path),
    });
  }

  const catalog = {
    generatedAt: process.env.SOURCE_DATE_EPOCH
      ? new Date(process.env.SOURCE_DATE_EPOCH * 1000).toISOString()
      : "2026-02-08T00:00:00.000Z",
    total: catalogSkills.length,
    skills: catalogSkills.sort((a, b) =>
      a.id < b.id ? -1 : a.id > b.id ? 1 : 0,
    ),
  };

  const aliases = buildAliases(catalog.skills);
  const bundleData = buildBundles(catalog.skills);

  const catalogPath = path.join(ROOT, "data", "catalog.json");
  const catalogMarkdownPath = path.join(ROOT, "CATALOG.md");
  const bundlesPath = path.join(ROOT, "data", "bundles.json");
  const aliasesPath = path.join(ROOT, "data", "aliases.json");

  fs.writeFileSync(catalogPath, JSON.stringify(catalog, null, 2));
  fs.writeFileSync(catalogMarkdownPath, renderCatalogMarkdown(catalog));
  fs.writeFileSync(
    bundlesPath,
    JSON.stringify(
      { generatedAt: catalog.generatedAt, ...bundleData },
      null,
      2,
    ),
  );
  fs.writeFileSync(
    aliasesPath,
    JSON.stringify({ generatedAt: catalog.generatedAt, aliases }, null, 2),
  );

  return catalog;
}

if (require.main === module) {
  const catalog = buildCatalog();
  console.log(`Generated catalog for ${catalog.total} skills.`);
}

module.exports = {
  buildCatalog,
};
