/**
 * Tag taxonomy for hatch3r content files (v2 — Wave 1 of content-pack redesign).
 *
 * Three logically distinct facets, each driving a different filter decision:
 *
 *   1. Capability   — what the artifact does (formerly "workflow" + parts of "domain")
 *   2. Floor        — non-negotiable inclusion markers; bypass preset shaping entirely
 *   3. Context      — what kind of project/team the artifact fits (technical compatibility)
 *
 * Helper facets (customize, ui-ux-specialisation, cli-tool, cli-tool-category, language)
 * carry their own admission rules but are not part of the capability/floor/context triad.
 *
 * Filenames, CLI-tool category tags, and language tags continue to use the existing flat
 * string convention but are grouped into typed sets so callers can reason about them
 * without hard-coded enumerations.
 *
 * TODO(Wave 2 — content re-tagging): Wave 1 only swaps the filter pipeline. The 175
 * canonical artifacts still carry their legacy tag values (`core`, `team`, `solo`,
 * `greenfield`, `brownfield`, `security` as a plain tag, `ai` as a CLI category). These
 * legacy values are NOT in TAG_REGISTRY and therefore fail every facet predicate — items
 * relying on them will not match the capability gate or floor admission stage and will
 * appear MISSING from preset output until Wave 2 re-tags the corpus per
 * `.audit-workspace/council-D-architect.md` §4. Wave 3 then rewrites the test suite.
 */

// ── Capability tags (the artifact's job) ─────────────────────────
// Each artifact MUST carry at least one capability tag (post-Wave-2) for the preset's
// "what work does this preset cover?" decision to admit it.

export const TAG_PLANNING       = "planning";       // specs, ADRs, roadmaps
export const TAG_IMPLEMENTATION = "implementation"; // code writing, fixing, refactoring
export const TAG_REVIEW         = "review";         // code review, QA, audits
export const TAG_DEVOPS         = "devops";         // CI/CD, releases, deploy, observability
export const TAG_MAINTENANCE    = "maintenance";    // dep audits, health checks, learnings, handoffs
export const TAG_ORCHESTRATION  = "orchestration";  // the sub-agent pipeline itself (formerly "core")
export const TAG_BOARD          = "board";          // project board management
export const TAG_PERFORMANCE    = "performance";    // perf budgets, profiling
export const TAG_AI             = "ai";             // AI feature engineering (evals, prompt mgmt)

// ── Floor tags (non-negotiable inclusion) ────────────────────────
// Items carrying a floor:* tag are admitted in EVERY preset (except `custom`
// with an explicit ID list). They bypass preset shaping. Structural mechanism
// enforcing the maintainer's locked floor decision (security + UI/UX in every
// preset; pipeline-critical agents always present).

export const TAG_FLOOR_SECURITY = "floor:security"; // P6 — security & trust
export const TAG_FLOOR_UI_UX    = "floor:ui-ux";    // P1 — UI/UX excellence (includes a11y)
export const TAG_FLOOR_PROTOCOL = "floor:protocol"; // pipeline-critical (researcher, implementer, reviewer, fixer, test-writer)

// ── Context tags (technical compatibility) ───────────────────────
// Drive deterministic project-type / team-size filtering. These are NOT
// preferences — they are compatibility statements. If an item is tagged
// `ctx:greenfield-only`, it is unsafe in a brownfield project and is removed
// regardless of preset.

export const TAG_CTX_GREENFIELD_ONLY = "ctx:greenfield-only";
export const TAG_CTX_BROWNFIELD_ONLY = "ctx:brownfield-only";
export const TAG_CTX_TEAM_ONLY       = "ctx:team-only";
// Note: there is no `ctx:solo-only` — nothing in the corpus is solo-exclusive.

// ── Customize family (locked: standard + full only) ──────────────
// The `customize` capability is materially distinct from other capabilities
// because the maintainer locked it to specific presets. Encoded as its own
// facet so the preset DSL can express "include customize" declaratively
// (`ContentPreset.includeCustomize: boolean`).

export const TAG_CUSTOMIZE = "customize";

// ── UI/UX specialisation tags (sub-facet of floor:ui-ux) ─────────
// Retained for the task-router and rule scoping; they do not drive preset
// selection (the floor:ui-ux tag does that). Frontmatter authors apply both:
// `tags: [floor:ui-ux, a11y, frontend]`.

export const TAG_A11Y          = "a11y";
export const TAG_FRONTEND      = "frontend";
export const TAG_UI            = "ui";
export const TAG_UX            = "ux";
export const TAG_DESIGN_SYSTEM = "design-system";

// ── CLI tool tags ────────────────────────────────────────────────
export const TAG_CLI_TOOLS = "cli-tools";
export const TAG_OPT_IN    = "opt-in";
export const TAG_CAVEAT    = "caveat";
export const TAG_REFERENCE = "reference";

// CLI tool category tags — mirror the union in `src/cliTools/registry.ts::CliToolMeta["category"]`.
export const TAG_CAT_SEARCH      = "search";
export const TAG_CAT_JSON        = "json";
export const TAG_CAT_YAML        = "yaml";
export const TAG_CAT_GIT         = "git";
export const TAG_CAT_VIEW        = "view";
export const TAG_CAT_EDIT        = "edit";
export const TAG_CAT_ARCHIVE     = "archive";
export const TAG_CAT_DATA        = "data";
export const TAG_CAT_FORGE       = "forge";
export const TAG_CAT_BROWSER     = "browser";
export const TAG_CAT_CONTAINER   = "container";
export const TAG_CAT_AI          = "ai-cat";   // renamed from "ai" to disambiguate from capability tag
export const TAG_CAT_INTERACTIVE = "interactive";

// ── Language tags ────────────────────────────────────────────────
export const TAG_LANG_TYPESCRIPT = "lang:typescript";
export const TAG_LANG_PYTHON     = "lang:python";
export const TAG_LANG_GO         = "lang:go";
export const TAG_LANG_RUST       = "lang:rust";
export const TAG_LANG_JAVA       = "lang:java";
export const TAG_LANG_RUBY       = "lang:ruby";

// ── Facet registry — single source of truth ──────────────────────

/**
 * Tag values remain plain strings so frontmatter authoring is unchanged.
 * The TAG_REGISTRY below assigns each known tag to exactly one facet;
 * unknown / legacy tag values return `undefined` from `facetOf()` and are
 * skipped by every facet-predicate.
 */
export type ContentTag = string;

export type TagFacet =
  | "capability"
  | "floor"
  | "context"
  | "customize"
  | "ui-ux-specialisation"
  | "cli-tool"
  | "cli-tool-category"
  | "language";

/**
 * The single source of truth. Every recognised tag is registered with exactly
 * one facet. Callers do not enumerate tags by name — they ask `facetOf(tag)`
 * or `tagsForFacet(facet)`.
 */
export const TAG_REGISTRY: Record<string, TagFacet> = {
  [TAG_PLANNING]:       "capability",
  [TAG_IMPLEMENTATION]: "capability",
  [TAG_REVIEW]:         "capability",
  [TAG_DEVOPS]:         "capability",
  [TAG_MAINTENANCE]:    "capability",
  [TAG_ORCHESTRATION]:  "capability",
  [TAG_BOARD]:          "capability",
  [TAG_PERFORMANCE]:    "capability",
  [TAG_AI]:             "capability",

  [TAG_FLOOR_SECURITY]: "floor",
  [TAG_FLOOR_UI_UX]:    "floor",
  [TAG_FLOOR_PROTOCOL]: "floor",

  [TAG_CTX_GREENFIELD_ONLY]: "context",
  [TAG_CTX_BROWNFIELD_ONLY]: "context",
  [TAG_CTX_TEAM_ONLY]:       "context",

  [TAG_CUSTOMIZE]: "customize",

  [TAG_A11Y]:          "ui-ux-specialisation",
  [TAG_FRONTEND]:      "ui-ux-specialisation",
  [TAG_UI]:            "ui-ux-specialisation",
  [TAG_UX]:            "ui-ux-specialisation",
  [TAG_DESIGN_SYSTEM]: "ui-ux-specialisation",

  [TAG_CLI_TOOLS]: "cli-tool",
  [TAG_OPT_IN]:    "cli-tool",
  [TAG_CAVEAT]:    "cli-tool",
  [TAG_REFERENCE]: "cli-tool",

  [TAG_CAT_SEARCH]:      "cli-tool-category",
  [TAG_CAT_JSON]:        "cli-tool-category",
  [TAG_CAT_YAML]:        "cli-tool-category",
  [TAG_CAT_GIT]:         "cli-tool-category",
  [TAG_CAT_VIEW]:        "cli-tool-category",
  [TAG_CAT_EDIT]:        "cli-tool-category",
  [TAG_CAT_ARCHIVE]:     "cli-tool-category",
  [TAG_CAT_DATA]:        "cli-tool-category",
  [TAG_CAT_FORGE]:       "cli-tool-category",
  [TAG_CAT_BROWSER]:     "cli-tool-category",
  [TAG_CAT_CONTAINER]:   "cli-tool-category",
  [TAG_CAT_AI]:          "cli-tool-category",
  [TAG_CAT_INTERACTIVE]: "cli-tool-category",

  [TAG_LANG_TYPESCRIPT]: "language",
  [TAG_LANG_PYTHON]:     "language",
  [TAG_LANG_GO]:         "language",
  [TAG_LANG_RUST]:       "language",
  [TAG_LANG_JAVA]:       "language",
  [TAG_LANG_RUBY]:       "language",
};

export function facetOf(tag: string): TagFacet | undefined {
  return TAG_REGISTRY[tag];
}

export function tagsForFacet(facet: TagFacet): string[] {
  return Object.keys(TAG_REGISTRY).filter((t) => TAG_REGISTRY[t] === facet);
}

/** All registered tag values (no legacy tags). */
export const ALL_TAGS: string[] = Object.keys(TAG_REGISTRY);

/** Convenience predicates used by resolveSelection (no hard-coded string lists). */
export const isCapabilityTag      = (t: string): boolean => facetOf(t) === "capability";
export const isFloorTag           = (t: string): boolean => facetOf(t) === "floor";
export const isContextTag         = (t: string): boolean => facetOf(t) === "context";
export const isCustomizeTag       = (t: string): boolean => facetOf(t) === "customize";
export const isUiUxSpecialisation = (t: string): boolean => facetOf(t) === "ui-ux-specialisation";
export const isLanguageTag        = (t: string): boolean => facetOf(t) === "language";

// ── Language helpers ─────────────────────────────────────────────

/**
 * Map detected language names to their corresponding language tags.
 * Used by resolveSelection to filter content by project language (Finding #71).
 */
export const LANGUAGE_TO_TAG: Record<string, string> = {
  typescript: TAG_LANG_TYPESCRIPT,
  javascript: TAG_LANG_TYPESCRIPT, // JS projects also benefit from TS rules
  python:     TAG_LANG_PYTHON,
  go:         TAG_LANG_GO,
  rust:       TAG_LANG_RUST,
  java:       TAG_LANG_JAVA,
  kotlin:     TAG_LANG_JAVA,       // Kotlin shares Java ecosystem
  ruby:       TAG_LANG_RUBY,
};

/**
 * Resolve a list of detected project language names to the set of `lang:*`
 * content tags that should match. Unknown languages are silently dropped.
 *
 * Example: `resolveLanguageTags(["typescript", "python"])`
 *   → `Set { "lang:typescript", "lang:python" }`
 */
export function resolveLanguageTags(projectLanguages: readonly string[]): Set<string> {
  const result = new Set<string>();
  for (const lang of projectLanguages) {
    const tag = LANGUAGE_TO_TAG[lang];
    if (tag) result.add(tag);
  }
  return result;
}

/**
 * Filter a list of items by language tags.
 *
 * Rules:
 * 1. Items marked `protected: true` always pass (universal opt-out from filtering).
 * 2. Items with no `lang:*` tags are language-agnostic and always pass.
 * 3. Items with `lang:*` tags pass only when at least one of their language tags
 *    is in the relevant set derived from `projectLanguages`.
 *
 * Returns `items` unchanged when `projectLanguages` is empty (filter is a no-op).
 *
 * @param items - The items to filter. Each must expose `tags: string[]` and
 *                an optional `protected: boolean`.
 * @param projectLanguages - The detected project languages (e.g. `["typescript"]`).
 */
export function filterByLanguages<T extends { tags: string[]; protected?: boolean }>(
  items: readonly T[],
  projectLanguages: readonly string[],
): T[] {
  if (projectLanguages.length === 0) return [...items];
  const relevant = resolveLanguageTags(projectLanguages);
  return items.filter((item) => {
    if (item.protected) return true;
    const itemLangTags = item.tags.filter(isLanguageTag);
    if (itemLangTags.length === 0) return true;
    return itemLangTags.some((t) => relevant.has(t));
  });
}
