// Explicit Mapping-Registry (Wertstrom P6, KAR-878/KAR-986, execution-prompt
// §14.3). §14.3 gives a STARTER list ("Do not base the complete
// implementation only on these mappings. Validate them across the complete
// corpus.") — this registry is that starter list, extended and VALIDATED
// against every one of the 23 real node classes + 2 real link classes found
// in the confidential corpus (local-only schema scan, KORPUS-REPORT.md
// "Node-Klassen-Zensus"). `internal/__tests__/mapping-registry-coverage.
// real-corpus.test.ts` asserts this registry has an entry for every class
// the real corpus actually contains — never silently unmapped.
//
// `VsmNode.type` (lib/vsm-types.ts) is a narrow, pre-existing 7-value union
// with no "parallel process"/"paced process"/"assembly"/"PPS"/"annotation"
// member — extending it is an editor/rendering change (new colors in
// vsm-config.ts, new canvas shape in vsm-editor.tsx) that Capability-Matrix.md
// assigns to later phases (A18 Kaizen-Marker is explicitly P8), not P6
// ("Parser+Familien+Preview+Mapping-Registry+Fixtures"). So several classes
// below deliberately GENERALIZE onto an existing type rather than invent a
// new one — always declared via `confidence < 1` + `generalizedNote`, never
// silently. Classes with no reasonable existing-type target are `supported:
// false` — counted and reported (§14.2/6 "list unsupported fields", §14.4
// "unsupported entities"), never dropped silently, never fabricated onto an
// unrelated node type.

import type { ConnectionKind, InventoryKind, NodeType } from '@/lib/vsm-types'

export const MAPPING_VERSION = 'simvsm-1'

export interface NodeMappingEntry {
  supported: true
  targetType: NodeType
  targetInventoryKind?: InventoryKind
  /** P8.2a (Baustein 2 "PPS als echtes Datenfeld", KAR-878/KAR-986) — mirrors
   * `targetInventoryKind`'s pattern: when set, `node-mapper.ts` sets
   * `isPps: true` on the mapped `VsmNode` (in addition to the `targetType`
   * generalization below). Only ever `true` (same true-only field shape as
   * `VsmNode.isPps` itself). */
  targetIsPps?: true
  /** 1.0 = direct/unambiguous. Below 1.0 always pairs with `generalizedNote`
   * explaining the simplification — shown only in the Import-Report's
   * advanced "transformed entities" section (§14.1: no technical mapping
   * detail unasked-for in the simple view). */
  confidence: number
  generalizedNote?: string
  labelDe: string
}

export interface UnsupportedMappingEntry {
  supported: false
  confidence: 0
  labelDe: string
  reasonDe: string
}

export type MappingEntry = NodeMappingEntry | UnsupportedMappingEntry

/** category:'item' node classes — the real VSM elements. Keys are SimVSM's
 * own `class` values (generic tool vocabulary, not customer data). */
export const NODE_MAPPING_REGISTRY: Record<string, MappingEntry> = {
  singleProcess: { supported: true, targetType: 'process', confidence: 1.0, labelDe: 'Prozess' },
  multiProcess: {
    supported: true,
    targetType: 'process',
    confidence: 0.8,
    generalizedNote: 'Parallelprozess (SimVSM multiProcess) wird als einfacher Prozess übernommen — kein eigener Parallel-Prozess-Typ im Datenmodell.',
    labelDe: 'Prozess (aus Parallelprozess)',
  },
  clockedProcess: {
    supported: true,
    targetType: 'process',
    confidence: 0.8,
    generalizedNote: 'Getakteter Prozess (SimVSM clockedProcess) wird als einfacher Prozess übernommen — kein eigener Takt-Prozess-Typ im Datenmodell.',
    labelDe: 'Prozess (aus getaktetem Prozess)',
  },
  joinProcess: {
    supported: true,
    targetType: 'process',
    confidence: 0.8,
    generalizedNote: 'Montage-/Join-Prozess (SimVSM joinProcess, inkl. Stückliste) wird als einfacher Prozess übernommen — die Stückliste (PartsListTable) wird nicht übernommen.',
    labelDe: 'Prozess (aus Montage-Prozess)',
  },
  leadProcess: {
    supported: true,
    targetType: 'process',
    confidence: 0.8,
    generalizedNote: 'Leitprozess (SimVSM leadProcess) wird als einfacher Prozess übernommen.',
    labelDe: 'Prozess (aus Leitprozess)',
  },
  productionControl: {
    supported: true,
    targetType: 'process',
    // P8.2a (Baustein 2, KAR-878/KAR-986): explicit PPS marker — narrows
    // (does not close) the TODO.md "kein eigener PPS-Typ im Datenmodell" gap.
    // See node-mapper.ts.
    targetIsPps: true,
    confidence: 0.6,
    generalizedNote:
      'Produktionssteuerung/PPS (SimVSM productionControl) wird als nicht-wertschöpfender Prozess angenähert — kein eigener PPS-Typ im Datenmodell (seit P8.2a aber mit isPps=true markiert, siehe VsmNode.isPps). Alternative wäre Verwerfen, das aber die oft anhängenden Informationsfluss-Kanten verwaisen ließe.',
    labelDe: 'Prozess (aus Produktionssteuerung/PPS)',
  },
  inventory: { supported: true, targetType: 'inventory', confidence: 1.0, labelDe: 'Bestand' },
  fifoStore: { supported: true, targetType: 'inventory', targetInventoryKind: 'fifo', confidence: 1.0, labelDe: 'Bestand (FIFO)' },
  supermarketStore: { supported: true, targetType: 'inventory', targetInventoryKind: 'supermarket', confidence: 1.0, labelDe: 'Bestand (Supermarkt)' },
  inventoryPush: { supported: true, targetType: 'inventory', targetInventoryKind: 'push', confidence: 1.0, labelDe: 'Bestand (Push)' },
  customer: { supported: true, targetType: 'customer', confidence: 1.0, labelDe: 'Kunde' },
  supplier: { supported: true, targetType: 'supplier', confidence: 1.0, labelDe: 'Lieferant' },
  externalMaterialTransport: { supported: true, targetType: 'transport', confidence: 0.9, labelDe: 'Transport (extern)' },
  internalMaterialTransport: { supported: true, targetType: 'transport', confidence: 0.9, labelDe: 'Transport (intern)' },

  // ── Unsupported: annotation/marker/visual classes ─────────────────────────
  // No annotation/Kaizen/shape NodeType exists (see file header). Counted,
  // never fabricated onto an unrelated type, never silently dropped.
  customText: { supported: false, confidence: 0, labelDe: 'Freitext-Element', reasonDe: 'Reines Canvas-Textelement, kein VSM-Datenobjekt — im aktuellen Datenmodell nicht abbildbar.' },
  noteAnnotation: { supported: false, confidence: 0, labelDe: 'Anmerkung', reasonDe: 'Anmerkungs-Element — dem Datenmodell fehlt ein Notiz-/Anmerkungs-Typ (Editor-Ausbau ist Capability-Matrix P8-Scope).' },
  noteVSM: { supported: false, confidence: 0, labelDe: 'Kaizen-Hinweis', reasonDe: 'Kaizen-Blitz-Element — dem Datenmodell fehlt ein Kaizen-/Maßnahmen-Typ (Capability-Matrix A18, explizit P8-Scope).' },
  shapeRectangle: { supported: false, confidence: 0, labelDe: 'Form (Rechteck)', reasonDe: 'Freie Zeichenform ohne VSM-Semantik — bewusst nicht übernommen (Capability-Matrix REJECT: keine Formen-Bibliothek).' },
  lightningNote: { supported: false, confidence: 0, labelDe: 'Blitz-Marker', reasonDe: 'Visueller Marker ohne eigene Daten — bewusst nicht übernommen (Capability-Matrix REJECT).' },
  exclamationPointNote: { supported: false, confidence: 0, labelDe: 'Ausrufezeichen-Marker', reasonDe: 'Visueller Marker ohne eigene Daten — bewusst nicht übernommen (Capability-Matrix REJECT).' },
  bottleneck: { supported: false, confidence: 0, labelDe: 'Engpass-Marker', reasonDe: 'Manuell gesetzter Engpass-Marker (keine Kennzahl) — SupplierPulse berechnet Engpässe selbst (lib/vsm-engine computeBottleneckV2), übernimmt keine manuellen Marker.' },
  image: { supported: false, confidence: 0, labelDe: 'Foto', reasonDe: 'Bild-Anhang an einen Knoten — außerhalb des Scopes (kein SVG-/Bild-Rendering-Import).' },
  foreignOrders: { supported: false, confidence: 0, labelDe: 'Fremdaufträge', reasonDe: 'Selten genutztes Sonderelement — bewusst nicht übernommen (Capability-Matrix REJECT).' },
}

export interface LinkMappingEntry {
  supported: boolean
  targetKind?: ConnectionKind
  labelDe: string
  reasonDe?: string
}

export const LINK_MAPPING_REGISTRY: Record<string, LinkMappingEntry> = {
  // Absent kind = materialFlow (lib/vsm-types.ts ConnectionKind doc) — never
  // written as an explicit literal, matching the rest of the codebase's
  // "absence is the default" discipline.
  materialFlow: { supported: true, targetKind: undefined, labelDe: 'Materialfluss' },
  informationFlow: { supported: true, targetKind: 'information', labelDe: 'Informationsfluss' },
  image: { supported: false, labelDe: 'Bild-Verknüpfung', reasonDe: 'Verknüpfung eines Foto-Anhangs an einen Knoten — außerhalb des Scopes.' },
}

/** category values that are never `'item'` VSM elements — purely visual
 * canvas furniture. Used by the parser to classify without needing the full
 * registry (a fast pre-filter; the registry is still authoritative for the
 * per-class mapping decision). */
export const NON_ITEM_CATEGORIES = new Set(['text', 'shape', 'group'])

export function classifyNode(simvsmClass: string): MappingEntry | undefined {
  return NODE_MAPPING_REGISTRY[simvsmClass]
}

export function classifyLink(simvsmClass: string): LinkMappingEntry | undefined {
  return LINK_MAPPING_REGISTRY[simvsmClass]
}

/** §14.3 "Validate them across the complete corpus": given the real corpus's
 * observed class -> occurrence-count map (produced by the real-corpus test,
 * never hardcoded), report which classes the registry does NOT know about.
 * A non-empty `unknownClasses` result means the corpus contains a node/link
 * class this module has never seen — the registry (not the corpus/test) is
 * what would need to grow. */
export function findUnknownNodeClasses(observedClassCounts: Readonly<Record<string, number>>): string[] {
  return Object.keys(observedClassCounts).filter((cls) => !(cls in NODE_MAPPING_REGISTRY))
}

export function findUnknownLinkClasses(observedClassCounts: Readonly<Record<string, number>>): string[] {
  return Object.keys(observedClassCounts).filter((cls) => !(cls in LINK_MAPPING_REGISTRY))
}
