import { describe, it, expect } from 'vitest'
import {
  NODE_MAPPING_REGISTRY,
  LINK_MAPPING_REGISTRY,
  MAPPING_VERSION,
  classifyNode,
  classifyLink,
  findUnknownNodeClasses,
  findUnknownLinkClasses,
} from '../mapping-registry'

// The 23 real node classes + 2 real link classes found in the confidential
// corpus (local-only schema scan, KORPUS-REPORT.md "Node-Klassen-Zensus").
// Listed here as GENERIC SimVSM tool vocabulary only (also in §14.3's own
// examples) — see README.md "Confidentiality". This list is the contract
// the real-corpus test (mapping-registry-coverage.real-corpus.test.ts)
// verifies against the ACTUAL corpus at run time — kept in sync manually
// here as a fast, DB/corpus-free regression lock.
const REAL_CORPUS_NODE_CLASSES = [
  'singleProcess', 'fifoStore', 'inventory', 'noteAnnotation', 'inventoryPush', 'internalMaterialTransport',
  'supplier', 'externalMaterialTransport', 'customer', 'productionControl', 'customText', 'image',
  'joinProcess', 'multiProcess', 'supermarketStore', 'noteVSM', 'shapeRectangle', 'bottleneck',
  'clockedProcess', 'leadProcess', 'foreignOrders', 'lightningNote', 'exclamationPointNote',
]
const REAL_CORPUS_LINK_CLASSES = ['materialFlow', 'informationFlow', 'image']

describe('mapping-registry', () => {
  it('has an entry for all 23 real corpus node classes', () => {
    expect(REAL_CORPUS_NODE_CLASSES).toHaveLength(23)
    for (const cls of REAL_CORPUS_NODE_CLASSES) {
      expect(NODE_MAPPING_REGISTRY[cls], `missing registry entry for node class "${cls}"`).toBeDefined()
    }
  })

  it('has an entry for all 3 real corpus link classes', () => {
    for (const cls of REAL_CORPUS_LINK_CLASSES) {
      expect(LINK_MAPPING_REGISTRY[cls], `missing registry entry for link class "${cls}"`).toBeDefined()
    }
  })

  it('findUnknownNodeClasses returns empty for the full real-corpus class set', () => {
    const counts = Object.fromEntries(REAL_CORPUS_NODE_CLASSES.map((c) => [c, 1]))
    expect(findUnknownNodeClasses(counts)).toEqual([])
  })

  it('findUnknownNodeClasses flags a class the registry has never seen', () => {
    expect(findUnknownNodeClasses({ someBrandNewClass: 3 })).toEqual(['someBrandNewClass'])
  })

  it('findUnknownLinkClasses returns empty for the full real-corpus link set', () => {
    const counts = Object.fromEntries(REAL_CORPUS_LINK_CLASSES.map((c) => [c, 1]))
    expect(findUnknownLinkClasses(counts)).toEqual([])
  })

  it('every supported node entry has confidence in (0,1]', () => {
    for (const [cls, entry] of Object.entries(NODE_MAPPING_REGISTRY)) {
      if (entry.supported) {
        expect(entry.confidence, cls).toBeGreaterThan(0)
        expect(entry.confidence, cls).toBeLessThanOrEqual(1)
      } else {
        expect(entry.confidence, cls).toBe(0)
      }
    }
  })

  it('classifyNode/classifyLink are undefined for a truly unknown class', () => {
    expect(classifyNode('totallyMadeUpClass')).toBeUndefined()
    expect(classifyLink('totallyMadeUpClass')).toBeUndefined()
  })

  it('inventory sub-kinds map to the correct InventoryKind', () => {
    expect(NODE_MAPPING_REGISTRY.fifoStore).toMatchObject({ supported: true, targetInventoryKind: 'fifo' })
    expect(NODE_MAPPING_REGISTRY.supermarketStore).toMatchObject({ supported: true, targetInventoryKind: 'supermarket' })
    expect(NODE_MAPPING_REGISTRY.inventoryPush).toMatchObject({ supported: true, targetInventoryKind: 'push' })
    expect(NODE_MAPPING_REGISTRY.inventory).toMatchObject({ supported: true })
    expect((NODE_MAPPING_REGISTRY.inventory as { targetInventoryKind?: string }).targetInventoryKind).toBeUndefined()
  })

  // P8.2a (Baustein 2 "PPS als echtes Datenfeld", KAR-878/KAR-986)
  it('productionControl carries targetIsPps: true; no other entry does', () => {
    expect(NODE_MAPPING_REGISTRY.productionControl).toMatchObject({ supported: true, targetIsPps: true })
    for (const [cls, entry] of Object.entries(NODE_MAPPING_REGISTRY)) {
      if (cls === 'productionControl') continue
      expect((entry as { targetIsPps?: true }).targetIsPps, cls).toBeUndefined()
    }
  })

  it('informationFlow maps to ConnectionKind "information"; materialFlow is absent (default)', () => {
    expect(LINK_MAPPING_REGISTRY.informationFlow).toMatchObject({ supported: true, targetKind: 'information' })
    expect(LINK_MAPPING_REGISTRY.materialFlow.targetKind).toBeUndefined()
  })

  it('annotation/marker classes explicitly rejected by Capability-Matrix are unsupported', () => {
    for (const cls of ['shapeRectangle', 'lightningNote', 'exclamationPointNote', 'foreignOrders', 'bottleneck', 'image']) {
      expect(NODE_MAPPING_REGISTRY[cls].supported, cls).toBe(false)
    }
  })

  it('exposes a stable MAPPING_VERSION', () => {
    expect(MAPPING_VERSION).toBe('simvsm-1')
  })
})
