import { describe, expect, it } from 'vitest'
import {
  OrgKnowledgeNodeSchema,
  OrgKnowledgeKindSchema,
  KnowledgeDomainSchema,
  KnowledgeLinkSchema,
  KnowledgeTargetKindSchema,
  KnowledgeTargetRefSchema
} from '../domains/knowledge'
import { OrganizationGraphEdgeKindSchema } from '../graph/schema'
import { buildOrganizationGraph } from '../graph/build'
import { DEFAULT_ORGANIZATION_MODEL, DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE } from '../defaults'
import { resolveOrganizationModel } from '../resolve'
import { compileOrganizationOntology } from '../ontology'
import { byOntology, governedBy, parsePath } from '../../knowledge/queries'
import type { OrganizationModel } from '../types'

// ---------------------------------------------------------------------------
// OrgKnowledgeNodeSchema â€” shape and validation
// ---------------------------------------------------------------------------

describe('OrgKnowledgeNodeSchema', () => {
  function makeNode(kind: string) {
    return {
      id: `knowledge.test-${kind}`,
      kind,
      title: `Test ${kind}`,
      summary: `A test ${kind} knowledge node.`,
      body: `## Body\n\nContent for ${kind}.`,
      links: [],
      ownerIds: [],
      updatedAt: '2026-05-01'
    }
  }

  it('accepts kind: playbook', () => {
    expect(() => OrgKnowledgeNodeSchema.parse(makeNode('playbook'))).not.toThrow()
  })

  it('accepts kind: strategy', () => {
    expect(() => OrgKnowledgeNodeSchema.parse(makeNode('strategy'))).not.toThrow()
  })

  it('accepts kind: reference', () => {
    expect(() => OrgKnowledgeNodeSchema.parse(makeNode('reference'))).not.toThrow()
  })

  it('rejects unknown kind', () => {
    const result = OrgKnowledgeNodeSchema.safeParse(makeNode('guide'))
    expect(result.success).toBe(false)
  })

  it('rejects missing required fields', () => {
    const result = OrgKnowledgeNodeSchema.safeParse({ id: 'knowledge.x', kind: 'playbook' })
    expect(result.success).toBe(false)
  })

  it('defaults links to empty array when omitted', () => {
    const node = OrgKnowledgeNodeSchema.parse({
      id: 'knowledge.test-default-links',
      kind: 'reference',
      title: 'Test',
      summary: 'Test summary.',
      body: 'Content.',
      updatedAt: '2026-05-01'
    })
    expect(node.links).toEqual([])
  })

  it('defaults ownerIds to empty array when omitted', () => {
    const node = OrgKnowledgeNodeSchema.parse({
      id: 'knowledge.test-default-owners',
      kind: 'strategy',
      title: 'Test',
      summary: 'Test summary.',
      body: 'Content.',
      updatedAt: '2026-05-01'
    })
    expect(node.ownerIds).toEqual([])
  })

  it('accepts role ids as knowledge owners', () => {
    const node = OrgKnowledgeNodeSchema.parse({
      ...makeNode('strategy'),
      ownerIds: ['role.ops-lead', 'role.ceo']
    })

    expect(node.ownerIds).toEqual(['role.ops-lead', 'role.ceo'])
  })

  it('accepts an optional semantic icon token', () => {
    const node = OrgKnowledgeNodeSchema.parse({
      ...makeNode('playbook'),
      icon: 'playbook'
    })

    expect(node.icon).toBe('playbook')
  })

  it('rejects an unknown icon token', () => {
    const result = OrgKnowledgeNodeSchema.safeParse({
      ...makeNode('reference'),
      icon: 'book'
    })

    expect(result.success).toBe(false)
  })

  it('accepts an optional externalUrl', () => {
    const node = OrgKnowledgeNodeSchema.parse({
      ...makeNode('reference'),
      externalUrl: 'https://docs.elevasis.com/technical/architecture'
    })

    expect(node.externalUrl).toBe('https://docs.elevasis.com/technical/architecture')
  })

  it('rejects an invalid externalUrl', () => {
    const result = OrgKnowledgeNodeSchema.safeParse({
      ...makeNode('reference'),
      externalUrl: 'not-a-url'
    })

    expect(result.success).toBe(false)
  })

  it('accepts an optional generated sourceFilePath', () => {
    const node = OrgKnowledgeNodeSchema.parse({
      ...makeNode('reference'),
      sourceFilePath: 'packages/elevasis-core/src/knowledge/nodes/platform/reference.mdx'
    })

    expect(node.sourceFilePath).toBe('packages/elevasis-core/src/knowledge/nodes/platform/reference.mdx')
  })
})

describe('resolveOrganizationModel with knowledge owner roles', () => {
  const node = {
    id: 'knowledge.test-owner',
    kind: 'playbook' as const,
    title: 'Owned Knowledge',
    summary: 'A knowledge node with role ownership.',
    body: '## Body\n\nContent.',
    ownerIds: ['role.ops-lead'],
    updatedAt: '2026-05-08'
  }

  it('passes when ownerIds reference declared role ids', () => {
    expect(() =>
      resolveOrganizationModel({
        roles: { 'role.ops-lead': { id: 'role.ops-lead', order: 10, title: 'Ops Lead' } },
        // Phase 4: knowledge is a flat Record<id, OrgKnowledgeNode>
        knowledge: { 'knowledge.test-owner': node }
      })
    ).not.toThrow()
  })

  it('throws when ownerIds reference unknown role ids', () => {
    expect(() =>
      resolveOrganizationModel({
        knowledge: { 'knowledge.test-owner': node }
      })
    ).toThrow(/unknown owner role/)
  })
})

describe('resolveOrganizationModel with ontology knowledge targets', () => {
  it('accepts knowledge links that directly target compiled ontology records', () => {
    expect(() =>
      resolveOrganizationModel({
        systems: {
          'sales.crm': {
            id: 'sales.crm',
            order: 10,
            label: 'CRM',
            enabled: true,
            ontology: {
              objectTypes: {
                'sales.crm:object/deal': {
                  id: 'sales.crm:object/deal',
                  label: 'Deal'
                }
              }
            }
          }
        },
        knowledge: {
          'knowledge.deal-policy': {
            id: 'knowledge.deal-policy',
            kind: 'reference',
            title: 'Deal Policy',
            summary: 'How deal records are governed.',
            body: 'Deal policy.',
            links: [{ target: { kind: 'ontology', id: 'sales.crm:object/deal' } }],
            updatedAt: '2026-05-14'
          }
        }
      })
    ).not.toThrow()
  })

  it('rejects knowledge links to unknown ontology records', () => {
    expect(() =>
      resolveOrganizationModel({
        knowledge: {
          'knowledge.missing-ontology': {
            id: 'knowledge.missing-ontology',
            kind: 'reference',
            title: 'Missing Ontology',
            summary: 'References a missing ontology record.',
            body: 'Missing.',
            links: [{ target: { kind: 'ontology', id: 'sales.crm:object/missing' } }],
            updatedAt: '2026-05-14'
          }
        }
      })
    ).toThrow(/unknown ontology target/)
  })

  it('compiles authored ontology targets without requiring legacy provenance fields', () => {
    const model = resolveOrganizationModel({
      systems: {
        'sales.crm': {
          id: 'sales.crm',
          order: 10,
          label: 'CRM',
          enabled: true,
          ontology: {
            objectTypes: {
              'sales.crm:object/deal': {
                id: 'sales.crm:object/deal',
                label: 'Deal'
              }
            },
            actionTypes: {
              'sales.crm:action/update-deal': {
                id: 'sales.crm:action/update-deal',
                label: 'Update Deal',
                actsOn: ['sales.crm:object/deal']
              }
            },
            catalogTypes: {
              'sales.crm:catalog/pipeline': {
                id: 'sales.crm:catalog/pipeline',
                label: 'Pipeline',
                appliesTo: 'sales.crm:object/deal'
              }
            }
          }
        }
      },
      knowledge: {
        'knowledge.pipeline-policy': {
          id: 'knowledge.pipeline-policy',
          kind: 'reference',
          title: 'Pipeline Policy',
          summary: 'How pipeline ontology is governed.',
          body: 'Pipeline policy.',
          links: [{ target: { kind: 'ontology', id: 'sales.crm:catalog/pipeline' } }],
          updatedAt: '2026-05-14'
        }
      }
    })
    const compiled = compileOrganizationOntology(model)

    expect(compiled.diagnostics).toEqual([])
    expect(compiled.ontology.objectTypes['sales.crm:object/deal']).not.toHaveProperty('legacyEntityId')
    expect(compiled.ontology.actionTypes['sales.crm:action/update-deal']).not.toHaveProperty('legacyActionId')
    expect(compiled.ontology.catalogTypes['sales.crm:catalog/pipeline']).not.toHaveProperty('legacyContentId')
    expect(model.knowledge['knowledge.pipeline-policy']?.links[0]?.nodeId).toBe(
      'ontology:sales.crm:catalog/pipeline'
    )
  })
})

// ---------------------------------------------------------------------------
// OrgKnowledgeKindSchema â€” enum shape
// ---------------------------------------------------------------------------

describe('OrgKnowledgeKindSchema', () => {
  it('accepts all three valid kinds', () => {
    for (const kind of ['playbook', 'strategy', 'reference']) {
      expect(() => OrgKnowledgeKindSchema.parse(kind)).not.toThrow()
    }
  })

  it('rejects invalid kind', () => {
    expect(OrgKnowledgeKindSchema.safeParse('guide').success).toBe(false)
    expect(OrgKnowledgeKindSchema.safeParse('').success).toBe(false)
  })
})

// ---------------------------------------------------------------------------
// OrganizationGraphEdgeKindSchema â€” governs edge is present
// ---------------------------------------------------------------------------

describe('OrganizationGraphEdgeKindSchema', () => {
  it('includes governs as a valid edge kind', () => {
    expect(() => OrganizationGraphEdgeKindSchema.parse('governs')).not.toThrow()
  })
})

// ---------------------------------------------------------------------------
// DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE â€” Phase 4: flat Record<id, OrgKnowledgeNode> (D3).
// The wrapper shape { version, lastModified, nodes[] } was removed; versioning
// is in domainMetadata.knowledge. The default is an empty map {}.
// ---------------------------------------------------------------------------

describe('DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE', () => {
  it('is an empty object (flat map with no pre-seeded nodes)', () => {
    expect(DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE).toEqual({})
  })

  it('passes KnowledgeDomainSchema.parse without throwing', () => {
    expect(() => KnowledgeDomainSchema.parse(DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE)).not.toThrow()
  })

  it('does not have a .nodes array (wrapper shape was removed in Phase 4)', () => {
    expect(DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE).not.toHaveProperty('nodes')
  })

  it('does not have a .version field (moved to domainMetadata.knowledge)', () => {
    expect(DEFAULT_ORGANIZATION_MODEL_KNOWLEDGE).not.toHaveProperty('version')
  })
})

// ---------------------------------------------------------------------------
// buildOrganizationGraph â€” knowledge nodes + governs edges
// Synthetic OM authored via flat Record<id, OrgKnowledgeNode> per Phase 4 schema.
// ---------------------------------------------------------------------------

// Phase 4: knowledge is a flat Record<id, OrgKnowledgeNode> â€” no .nodes array wrapper.
const SYNTHETIC_OM: OrganizationModel = {
  ...DEFAULT_ORGANIZATION_MODEL,
  systems: {
    sales: {
      id: 'sales',
      order: 10,
      label: 'Sales',
      lifecycle: 'active'
    },
    'sales.crm': {
      id: 'sales.crm',
      order: 20,
      label: 'CRM',
      lifecycle: 'active',
      governedByKnowledge: ['knowledge.test-playbook-1']
    },
    'sales.lead-gen': {
      id: 'sales.lead-gen',
      order: 30,
      label: 'Lead Gen',
      lifecycle: 'active',
      governedByKnowledge: ['knowledge.test-playbook-1']
    }
  },
  knowledge: {
    'knowledge.test-playbook-1': {
      id: 'knowledge.test-playbook-1',
      kind: 'playbook',
      title: 'Test Playbook',
      summary: 'Test playbook summary.',
      body: '## Overview\n\nContent.',
      links: [
        { target: { kind: 'system', id: 'sales.crm' }, nodeId: 'system:sales.crm' },
        { target: { kind: 'system', id: 'sales.lead-gen' }, nodeId: 'system:sales.lead-gen' }
      ],
      ownerIds: [],
      updatedAt: '2026-01-01'
    },
    'knowledge.test-strategy-1': {
      id: 'knowledge.test-strategy-1',
      kind: 'strategy',
      title: 'Test Strategy',
      summary: 'Test strategy summary.',
      body: '## Strategy\n\nContent.',
      links: [],
      ownerIds: [],
      updatedAt: '2026-01-02'
    },
    'knowledge.test-reference-1': {
      id: 'knowledge.test-reference-1',
      kind: 'reference',
      title: 'Test Reference',
      summary: 'Test reference summary.',
      body: '## Reference\n\nContent.',
      links: [],
      ownerIds: [],
      updatedAt: '2026-01-03'
    }
  }
}

describe('buildOrganizationGraph with knowledge', () => {
  const graph = buildOrganizationGraph({ organizationModel: SYNTHETIC_OM })

  it('emits a knowledge node for each synthetic node', () => {
    const knowledgeNodes = graph.nodes.filter((n) => n.kind === 'knowledge')
    expect(knowledgeNodes.length).toBe(Object.keys(SYNTHETIC_OM.knowledge).length)
  })

  it('knowledge nodes carry sourceId matching the OM node id', () => {
    for (const omNode of Object.values(SYNTHETIC_OM.knowledge)) {
      const graphNode = graph.nodes.find((n) => n.sourceId === omNode.id)
      expect(graphNode).toBeDefined()
      expect(graphNode?.kind).toBe('knowledge')
      expect(graphNode?.label).toBe(omNode.title)
    }
  })

  it('emits governs edges for nodes that have links', () => {
    const governsEdges = graph.edges.filter((e) => e.kind === 'governs')
    const totalLinks = Object.values(SYNTHETIC_OM.knowledge).reduce((sum, n) => sum + n.links.length, 0)
    expect(governsEdges.length).toBe(totalLinks)
  })

  it('links targetId resolves to an existing graph node id for at least one node', () => {
    const nodeWithLinks = Object.values(SYNTHETIC_OM.knowledge).find((n) => n.links.length > 0)
    expect(nodeWithLinks).toBeDefined()

    const graphNodeIds = new Set(graph.nodes.map((n) => n.id))
    for (const link of nodeWithLinks!.links) {
      expect(graphNodeIds.has(link.nodeId)).toBe(true)
    }
  })

  it('DEFAULT_ORGANIZATION_MODEL produces zero knowledge nodes in graph', () => {
    const defaultGraph = buildOrganizationGraph({ organizationModel: DEFAULT_ORGANIZATION_MODEL })
    const defaultKnowledgeNodes = defaultGraph.nodes.filter((n) => n.kind === 'knowledge')
    expect(defaultKnowledgeNodes).toHaveLength(0)
  })

  it('emits governs edges from knowledge directly to ontology graph nodes', () => {
    const model = resolveOrganizationModel({
      systems: {
        'sales.crm': {
          id: 'sales.crm',
          order: 10,
          label: 'CRM',
          enabled: true,
          ontology: {
            objectTypes: {
              'sales.crm:object/deal': {
                id: 'sales.crm:object/deal',
                label: 'Deal'
              }
            }
          }
        }
      },
      knowledge: {
        'knowledge.deal-policy': {
          id: 'knowledge.deal-policy',
          kind: 'reference',
          title: 'Deal Policy',
          summary: 'How deal records are governed.',
          body: 'Deal policy.',
          links: [{ target: { kind: 'ontology', id: 'sales.crm:object/deal' } }],
          ownerIds: [],
          updatedAt: '2026-05-14'
        }
      }
    })
    const ontologyGraph = buildOrganizationGraph({ organizationModel: model })

    expect(
      ontologyGraph.edges.find(
        (edge) =>
          edge.kind === 'governs' &&
          edge.sourceId === 'knowledge:knowledge.deal-policy' &&
          edge.targetId === 'ontology:sales.crm:object/deal'
      )
    ).toBeDefined()
  })

  it('knowledge query helpers traverse ontology graph node IDs', () => {
    const model = resolveOrganizationModel({
      systems: {
        'sales.crm': {
          id: 'sales.crm',
          order: 10,
          label: 'CRM',
          enabled: true,
          ontology: {
            objectTypes: {
              'sales.crm:object/deal': {
                id: 'sales.crm:object/deal',
                label: 'Deal'
              }
            }
          }
        }
      },
      knowledge: {
        'knowledge.deal-policy': {
          id: 'knowledge.deal-policy',
          kind: 'reference',
          title: 'Deal Policy',
          summary: 'How deal records are governed.',
          body: 'Deal policy.',
          links: [{ target: { kind: 'ontology', id: 'sales.crm:object/deal' } }],
          ownerIds: [],
          updatedAt: '2026-05-14'
        }
      }
    })
    const ontologyGraph = buildOrganizationGraph({ organizationModel: model })
    const nodes = Object.values(model.knowledge)

    expect(byOntology(ontologyGraph, 'sales.crm:object/deal', nodes).map((node) => node.id)).toEqual([
      'knowledge.deal-policy'
    ])
    expect(governedBy(ontologyGraph, 'ontology:sales.crm:object/deal')).toEqual(['knowledge:knowledge.deal-policy'])
    expect(parsePath('/by-ontology/sales.crm:object/deal')).toEqual({
      mount: 'by-ontology',
      args: ['sales.crm:object/deal']
    })
  })
})

// ---------------------------------------------------------------------------
// KnowledgeLinkSchema â€” nodeId format validation
// ---------------------------------------------------------------------------

describe('KnowledgeLinkSchema', () => {
  it('accepts and normalizes a canonical typed target', () => {
    const link = KnowledgeLinkSchema.parse({ target: { kind: 'system', id: 'sales.crm' } })

    expect(link).toEqual({
      target: { kind: 'system', id: 'sales.crm' },
      nodeId: 'system:sales.crm'
    })
  })

  it('accepts and normalizes a legacy kind:dotted-path nodeId', () => {
    const link = KnowledgeLinkSchema.parse({ nodeId: 'system:sales.lead-gen' })

    expect(link).toEqual({
      target: { kind: 'system', id: 'sales.lead-gen' },
      nodeId: 'system:sales.lead-gen'
    })
  })

  it('accepts resource: and knowledge: prefixed node IDs', () => {
    expect(() => KnowledgeLinkSchema.parse({ nodeId: 'resource:my-resource' })).not.toThrow()
    expect(() => KnowledgeLinkSchema.parse({ nodeId: 'knowledge:knowledge.test-doc' })).not.toThrow()
  })

  it('rejects retired content-node prefixed node IDs', () => {
    expect(KnowledgeLinkSchema.safeParse({ nodeId: 'content-node:sales.crm:default-pipeline' }).success).toBe(false)
  })

  it('accepts and normalizes ontology graph node IDs', () => {
    const link = KnowledgeLinkSchema.parse({ nodeId: 'ontology:sales.crm:object/deal' })

    expect(link).toEqual({
      target: { kind: 'ontology', id: 'sales.crm:object/deal' },
      nodeId: 'ontology:sales.crm:object/deal'
    })
  })

  it('rejects a bare dotted ID with no kind: prefix', () => {
    expect(KnowledgeLinkSchema.safeParse({ nodeId: 'sales.crm' }).success).toBe(false)
  })

  it('rejects an empty nodeId', () => {
    expect(KnowledgeLinkSchema.safeParse({ nodeId: '' }).success).toBe(false)
  })

  it('rejects a nodeId with uppercase characters', () => {
    expect(KnowledgeLinkSchema.safeParse({ nodeId: 'system:Sales.CRM' }).success).toBe(false)
  })

  it('rejects a link missing the nodeId field', () => {
    expect(KnowledgeLinkSchema.safeParse({}).success).toBe(false)
  })

  it('rejects a plain number as nodeId', () => {
    expect(KnowledgeLinkSchema.safeParse({ nodeId: 123 }).success).toBe(false)
  })
})

describe('KnowledgeTargetRefSchema', () => {
  it('accepts modeled target kinds', () => {
    expect(KnowledgeTargetRefSchema.safeParse({ kind: 'system', id: 'sales.crm' }).success).toBe(true)
    expect(KnowledgeTargetRefSchema.safeParse({ kind: 'customer-segment', id: 'customer.enterprise' }).success).toBe(
      true
    )
  })

  it('rejects content-node as a retired target kind', () => {
    expect(KnowledgeTargetKindSchema.safeParse('content-node').success).toBe(false)
    expect(KnowledgeTargetRefSchema.safeParse({ kind: 'content-node', id: 'sales.crm:default-pipeline' }).success).toBe(
      false
    )
  })

  it('keeps ontology catalog targets as the supported replacement for content-node links', () => {
    const link = KnowledgeLinkSchema.parse({
      target: { kind: 'ontology', id: 'sales.crm:catalog/default-pipeline' }
    })

    expect(link).toEqual({
      target: { kind: 'ontology', id: 'sales.crm:catalog/default-pipeline' },
      nodeId: 'ontology:sales.crm:catalog/default-pipeline'
    })
  })

  it('accepts ontology as a target kind when the id is a valid ontology id', () => {
    expect(KnowledgeTargetKindSchema.safeParse('ontology').success).toBe(true)
    expect(KnowledgeTargetRefSchema.safeParse({ kind: 'ontology', id: 'sales.crm:object/deal' }).success).toBe(true)
  })

  it('rejects ontology targets with malformed ontology ids', () => {
    expect(KnowledgeTargetRefSchema.safeParse({ kind: 'ontology', id: 'sales.crm.deal' }).success).toBe(false)
  })

  it('rejects unknown target kinds', () => {
    expect(KnowledgeTargetKindSchema.safeParse('integration').success).toBe(false)
    expect(KnowledgeTargetRefSchema.safeParse({ kind: 'integration', id: 'hubspot' }).success).toBe(false)
  })
})

// ---------------------------------------------------------------------------
// KnowledgeDomainSchema â€” flat Record shape (Phase 4 D3)
// ---------------------------------------------------------------------------

describe('KnowledgeDomainSchema â€” flat Record<id, OrgKnowledgeNode>', () => {
  it('accepts an empty map', () => {
    expect(KnowledgeDomainSchema.safeParse({}).success).toBe(true)
  })

  it('defaults to empty map when undefined', () => {
    const result = KnowledgeDomainSchema.safeParse(undefined)
    expect(result.success).toBe(true)
    if (result.success) {
      expect(result.data).toEqual({})
    }
  })

  it('accepts a Record keyed by knowledge node ids', () => {
    const result = KnowledgeDomainSchema.safeParse({
      'knowledge.my-playbook': {
        id: 'knowledge.my-playbook',
        kind: 'playbook',
        title: 'My Playbook',
        summary: 'A test playbook.',
        body: '## Content',
        links: [],
        ownerIds: [],
        updatedAt: '2026-05-01'
      }
    })
    expect(result.success).toBe(true)
  })

  it('rejects the old wrapper shape { version, lastModified, nodes[] }', () => {
    // The old wrapper-with-array shape does not parse as a Record<id, OrgKnowledgeNode>
    const result = KnowledgeDomainSchema.safeParse({
      version: 1,
      lastModified: '2026-05-10',
      nodes: []
    })
    // Each key ('version', 'lastModified', 'nodes') would be parsed as a knowledge node id,
    // and the values are not valid OrgKnowledgeNodeSchema â€” so this should fail
    expect(result.success).toBe(false)
  })
})

// ---------------------------------------------------------------------------
// OrgKnowledgeNodeSchema â€” field length constraints
// ---------------------------------------------------------------------------

describe('OrgKnowledgeNodeSchema length constraints', () => {
  const BASE = {
    id: 'knowledge.test-node',
    kind: 'playbook',
    title: 'Test Node',
    summary: 'A valid summary.',
    body: 'Body content.',
    links: [],
    ownerIds: [],
    updatedAt: '2026-05-01'
  }

  it('rejects title exceeding 200 characters', () => {
    const result = OrgKnowledgeNodeSchema.safeParse({ ...BASE, title: 'x'.repeat(201) })
    expect(result.success).toBe(false)
  })

  it('accepts title exactly at 200 characters', () => {
    const result = OrgKnowledgeNodeSchema.safeParse({ ...BASE, title: 'x'.repeat(200) })
    expect(result.success).toBe(true)
  })

  it('rejects summary exceeding 1000 characters', () => {
    const result = OrgKnowledgeNodeSchema.safeParse({ ...BASE, summary: 'x'.repeat(1001) })
    expect(result.success).toBe(false)
  })

  it('accepts summary exactly at 1000 characters', () => {
    const result = OrgKnowledgeNodeSchema.safeParse({ ...BASE, summary: 'x'.repeat(1000) })
    expect(result.success).toBe(true)
  })

  it('rejects empty title', () => {
    const result = OrgKnowledgeNodeSchema.safeParse({ ...BASE, title: '' })
    expect(result.success).toBe(false)
  })

  it('rejects empty summary', () => {
    const result = OrgKnowledgeNodeSchema.safeParse({ ...BASE, summary: '' })
    expect(result.success).toBe(false)
  })

  it('rejects empty body', () => {
    const result = OrgKnowledgeNodeSchema.safeParse({ ...BASE, body: '' })
    expect(result.success).toBe(false)
  })

  it('rejects id with uppercase characters', () => {
    const result = OrgKnowledgeNodeSchema.safeParse({ ...BASE, id: 'Knowledge.Test' })
    expect(result.success).toBe(false)
  })

  it('rejects id exceeding 100 characters', () => {
    const result = OrgKnowledgeNodeSchema.safeParse({ ...BASE, id: 'knowledge.' + 'a'.repeat(95) })
    expect(result.success).toBe(false)
  })

  it('accepts a valid custom icon token on a node', () => {
    const result = OrgKnowledgeNodeSchema.safeParse({ ...BASE, icon: 'custom.my-icon' })
    expect(result.success).toBe(true)
  })

  it('trims whitespace from title and summary', () => {
    const node = OrgKnowledgeNodeSchema.parse({ ...BASE, title: '  Trimmed  ', summary: '  Summary.  ' })
    expect(node.title).toBe('Trimmed')
    expect(node.summary).toBe('Summary.')
  })
})
