/**
 * ResourceRegistry Integration Tests
 *
 * Tests the full registry lifecycle with real organization configs.
 * Pattern: CI-Safe Service Integration (Pattern 3) - runs in CI, no external deps.
 *
 * Tests:
 * - Organization config compliance with new ResourceDefinition schema
 * - Command View edge generation from consolidated vocabulary
 * - Serialization roundtrip
 * - Validation integration
 * - Multi-organization isolation
 */

import { describe, it, expect, beforeAll } from 'vitest'
import { z } from 'zod'
import { ResourceRegistry } from '../resource-registry'
import type { DeploymentSpec } from '../resource-registry'
import type {
  TriggerDefinition,
  IntegrationDefinition,
  ExternalResourceDefinition,
  HumanCheckpointDefinition,
  ResourceRelationships
} from '../types'
import type { WorkflowDefinition } from '../../../execution/engine/workflow/types'
import type { AgentDefinition } from '../../../execution/engine/agent/core/types'
import type { ModelConfig } from '../../../execution/engine/llm/model-info'

describe('ResourceRegistry Integration', () => {
  // ============================================================================
  // Mock Data Helpers
  // ============================================================================

  const createMockWorkflow = (resourceId: string, status: 'dev' | 'prod' = 'dev'): WorkflowDefinition => ({
    config: {
      resourceId,
      name: `Workflow ${resourceId}`,
      description: `Test workflow ${resourceId}`,
      version: '1.0.0',
      type: 'workflow',
      status
    },
    contract: {
      inputSchema: z.object({ data: z.string() }),
      outputSchema: z.object({ result: z.boolean() })
    },
    steps: {
      step1: {
        id: 'step1',
        name: 'First Step',
        description: 'First step',
        handler: async () => ({ result: true }),
        inputSchema: z.object({ data: z.string() }),
        outputSchema: z.object({ result: z.boolean() }),
        next: null
      }
    },
    entryPoint: 'step1'
  })

  const createMockAgent = (resourceId: string, status: 'dev' | 'prod' = 'dev'): AgentDefinition => ({
    config: {
      resourceId,
      name: `Agent ${resourceId}`,
      description: `Test agent ${resourceId}`,
      version: '1.0.0',
      type: 'agent',
      status,
      systemPrompt: 'You are a test agent'
    },
    contract: {
      inputSchema: z.object({ query: z.string() }),
      outputSchema: z.object({ response: z.string() })
    },
    tools: [],
    modelConfig: {
      provider: 'mock',
      apiKey: 'test-key',
      model: 'mock'
    } as ModelConfig
  })

  /**
   * Create comprehensive test organization exercising all resource types
   * and edge generation patterns
   */
  const createTestOrganization = (): DeploymentSpec => {
    const workflows = [
      createMockWorkflow('order-workflow', 'prod'),
      createMockWorkflow('support-workflow', 'dev')
    ]

    const agents = [
      createMockAgent('order-agent', 'prod'),
      createMockAgent('support-agent', 'dev')
    ]

    const triggers: TriggerDefinition[] = [
      {
        resourceId: 'trigger-webhook-order',
        type: 'trigger',
        triggerType: 'webhook',
        version: '1.0.0',
        name: 'Order Webhook',
        description: 'Webhook from Shopify on new orders',
        status: 'prod',
        webhookPath: '/webhooks/shopify/orders'
      },
      {
        resourceId: 'trigger-schedule-support',
        type: 'trigger',
        triggerType: 'schedule',
        version: '1.0.0',
        name: 'Support Ticket Check',
        description: 'Check for new support tickets every hour',
        status: 'dev',
        schedule: '0 * * * *'
      },
      {
        resourceId: 'trigger-manual-test',
        type: 'trigger',
        triggerType: 'manual',
        version: '1.0.0',
        name: 'Manual Test',
        description: 'Manual trigger for testing',
        status: 'dev'
      }
    ]

    const integrations: IntegrationDefinition[] = [
      {
        resourceId: 'integration-shopify',
        type: 'integration',
        version: '1.0.0',
        status: 'prod',
        provider: 'shopify',
        credentialName: 'shopify-prod',
        name: 'Shopify Production',
        description: 'E-commerce platform'
      },
      {
        resourceId: 'integration-zendesk',
        type: 'integration',
        version: '1.0.0',
        status: 'dev',
        provider: 'zendesk',
        credentialName: 'zendesk-dev',
        name: 'Zendesk Support',
        description: 'Support ticket system'
      }
    ]

    const externalResources: ExternalResourceDefinition[] = [
      {
        resourceId: 'external-n8n-sync',
        type: 'external',
        version: '1.0.0',
        platform: 'n8n',
        name: 'n8n Data Sync',
        description: 'Legacy n8n workflow for syncing data',
        status: 'dev',
        platformUrl: 'https://n8n.example.com/workflow/123',
        externalId: 'workflow-123',
        triggers: { workflows: ['support-workflow'] },
        uses: { integrations: ['integration-zendesk'] }
      },
      {
        resourceId: 'external-zapier-notify',
        type: 'external',
        version: '1.0.0',
        platform: 'zapier',
        name: 'Zapier Notifications',
        description: 'Zapier zap for sending notifications',
        status: 'prod',
        platformUrl: 'https://zapier.com/app/zap/456'
        // No triggeredBy - removed per relationship-consolidation design
      }
    ]

    const humanCheckpoints: HumanCheckpointDefinition[] = [
      {
        resourceId: 'approval-high-value',
        type: 'human',
        version: '1.0.0',
        name: 'High Value Order Approval',
        description: 'Approve orders over $10,000',
        status: 'prod',
        requestedBy: { agents: ['order-agent'] },
        routesTo: { workflows: ['order-workflow'] }
      },
      {
        resourceId: 'approval-escalation',
        type: 'human',
        version: '1.0.0',
        name: 'Support Escalation',
        description: 'Escalated support tickets requiring review',
        status: 'dev',
        requestedBy: { workflows: ['support-workflow'] }
        // No routesTo - optional field
      }
    ]

    const relationships: ResourceRelationships = {
      // Trigger relationships (moved from TriggerDefinition.triggers)
      'trigger-webhook-order': {
        triggers: { workflows: ['order-workflow'] }
      },
      'trigger-schedule-support': {
        triggers: { agents: ['support-agent'] }
      },
      'trigger-manual-test': {
        triggers: { workflows: ['order-workflow'] }
      },
      // Agent/Workflow relationships
      'order-agent': {
        uses: { integrations: ['integration-shopify'] },
        triggers: { workflows: ['order-workflow'] }
      },
      'support-agent': {
        uses: { integrations: ['integration-zendesk'] }
      },
      'order-workflow': {
        triggers: { agents: ['support-agent'] }
      }
    }

    return {
      workflows,
      agents,
      triggers,
      integrations,
      externalResources,
      humanCheckpoints,
      relationships
    }
  }

  // ============================================================================
  // Organization Config Compliance Tests
  // ============================================================================

  describe('Organization Config Compliance', () => {
    it('creates registry with all resource types without throwing', () => {
      const testOrg = createTestOrganization()

      expect(() => {
        new ResourceRegistry({ 'test-org': testOrg })
      }).not.toThrow()
    })

    it('all triggers have resourceId, version, type discriminator, triggerType', () => {
      const testOrg = createTestOrganization()
      const registry = new ResourceRegistry({ 'test-org': testOrg })

      const triggers = registry.getTriggers('test-org')

      expect(triggers.length).toBeGreaterThan(0)
      for (const trigger of triggers) {
        expect(trigger.resourceId).toBeDefined()
        expect(trigger.version).toBeDefined()
        expect(trigger.type).toBe('trigger')
        expect(trigger.triggerType).toBeDefined()
        expect(['webhook', 'schedule', 'manual', 'event']).toContain(trigger.triggerType)
      }
    })

    it('all integrations have resourceId, version, type, status', () => {
      const testOrg = createTestOrganization()
      const registry = new ResourceRegistry({ 'test-org': testOrg })

      const integrations = registry.getIntegrations('test-org')

      expect(integrations.length).toBeGreaterThan(0)
      for (const integration of integrations) {
        expect(integration.resourceId).toBeDefined()
        expect(integration.version).toBeDefined()
        expect(integration.type).toBe('integration')
        expect(integration.status).toBeDefined()
        expect(['dev', 'prod']).toContain(integration.status)
      }
    })

    it('all external resources have resourceId, version, type (no triggeredBy)', () => {
      const testOrg = createTestOrganization()
      const registry = new ResourceRegistry({ 'test-org': testOrg })

      const externalResources = registry.getExternalResources('test-org')

      expect(externalResources.length).toBeGreaterThan(0)
      for (const external of externalResources) {
        expect(external.resourceId).toBeDefined()
        expect(external.version).toBeDefined()
        expect(external.type).toBe('external')
        // Ensure triggeredBy field doesn't exist (removed in refactor)
        expect((external as unknown as { triggeredBy?: unknown }).triggeredBy).toBeUndefined()
      }
    })

    it('all human checkpoints have resourceId, version, type, description (required)', () => {
      const testOrg = createTestOrganization()
      const registry = new ResourceRegistry({ 'test-org': testOrg })

      const humanCheckpoints = registry.getHumanCheckpoints('test-org')

      expect(humanCheckpoints.length).toBeGreaterThan(0)
      for (const checkpoint of humanCheckpoints) {
        expect(checkpoint.resourceId).toBeDefined()
        expect(checkpoint.version).toBeDefined()
        expect(checkpoint.type).toBe('human')
        expect(checkpoint.description).toBeDefined()
        expect(checkpoint.description.length).toBeGreaterThan(0)
      }
    })
  })

  // ============================================================================
  // Command View Data Generation Tests
  // ============================================================================

  describe('Command View Data Generation', () => {
    let commandViewData: ReturnType<ResourceRegistry['getCommandViewData']>

    beforeAll(() => {
      const testOrg = createTestOrganization()
      const registry = new ResourceRegistry({ 'test-org': testOrg })
      commandViewData = registry.getCommandViewData('test-org')
    })

    it('generates edges from trigger.triggers declarations', () => {
      // trigger-webhook-order triggers order-workflow
      const edge1 = commandViewData.edges.find(
        (e) => e.source === 'trigger-webhook-order' && e.target === 'order-workflow'
      )
      expect(edge1).toBeDefined()
      expect(edge1?.relationship).toBe('triggers')

      // trigger-schedule-support triggers support-agent
      const edge2 = commandViewData.edges.find(
        (e) => e.source === 'trigger-schedule-support' && e.target === 'support-agent'
      )
      expect(edge2).toBeDefined()
      expect(edge2?.relationship).toBe('triggers')

      // trigger-manual-test triggers order-workflow
      const edge3 = commandViewData.edges.find(
        (e) => e.source === 'trigger-manual-test' && e.target === 'order-workflow'
      )
      expect(edge3).toBeDefined()
      expect(edge3?.relationship).toBe('triggers')
    })

    it('generates edges from resource relationships.triggers', () => {
      // order-agent triggers order-workflow
      const edge1 = commandViewData.edges.find((e) => e.source === 'order-agent' && e.target === 'order-workflow')
      expect(edge1).toBeDefined()
      expect(edge1?.relationship).toBe('triggers')

      // order-workflow triggers support-agent
      const edge2 = commandViewData.edges.find((e) => e.source === 'order-workflow' && e.target === 'support-agent')
      expect(edge2).toBeDefined()
      expect(edge2?.relationship).toBe('triggers')
    })

    it('generates edges from external.triggers declarations', () => {
      // external-n8n-sync triggers support-workflow
      const edge = commandViewData.edges.find(
        (e) => e.source === 'external-n8n-sync' && e.target === 'support-workflow'
      )
      expect(edge).toBeDefined()
      expect(edge?.relationship).toBe('triggers')
    })

    it('generates approval edges from humanCheckpoint.requestedBy', () => {
      // order-agent -> approval-high-value (approval edge)
      const edge1 = commandViewData.edges.find((e) => e.source === 'order-agent' && e.target === 'approval-high-value')
      expect(edge1).toBeDefined()
      expect(edge1?.relationship).toBe('approval')

      // support-workflow -> approval-escalation (approval edge)
      const edge2 = commandViewData.edges.find(
        (e) => e.source === 'support-workflow' && e.target === 'approval-escalation'
      )
      expect(edge2).toBeDefined()
      expect(edge2?.relationship).toBe('approval')
    })

    it('generates triggers edges from humanCheckpoint.routesTo', () => {
      // approval-high-value -> order-workflow (triggers edge after approval)
      const edge = commandViewData.edges.find(
        (e) => e.source === 'approval-high-value' && e.target === 'order-workflow'
      )
      expect(edge).toBeDefined()
      expect(edge?.relationship).toBe('triggers')
    })

    it('does NOT generate edges from triggeredBy (removed)', () => {
      // No edges should exist with triggeredBy as source field (field was removed)
      const allEdges = commandViewData.edges

      // Verify no edge uses triggeredBy logic
      // In old system, external-zapier-notify might have had triggeredBy: { agents: ['order-agent'] }
      // which would create order-agent -> external-zapier-notify edge
      // This should NOT exist now
      const oldStyleEdge = allEdges.find((e) => e.source === 'order-agent' && e.target === 'external-zapier-notify')
      expect(oldStyleEdge).toBeUndefined()
    })

    it('all edges have valid relationship types (triggers, uses, approval)', () => {
      const validRelationships = ['triggers', 'uses', 'approval']

      for (const edge of commandViewData.edges) {
        expect(validRelationships).toContain(edge.relationship)
      }
    })

    it('no edges have relationship type invokes', () => {
      // 'invokes' was renamed to 'triggers' - ensure no old relationship type exists
      const invokesEdges = commandViewData.edges.filter(
        (e) => (e as unknown as { relationship: string }).relationship === 'invokes'
      )
      expect(invokesEdges).toHaveLength(0)
    })

    it('generates uses edges from relationships.uses', () => {
      // order-agent uses integration-shopify
      const edge1 = commandViewData.edges.find((e) => e.source === 'order-agent' && e.target === 'integration-shopify')
      expect(edge1).toBeDefined()
      expect(edge1?.relationship).toBe('uses')

      // support-agent uses integration-zendesk
      const edge2 = commandViewData.edges.find(
        (e) => e.source === 'support-agent' && e.target === 'integration-zendesk'
      )
      expect(edge2).toBeDefined()
      expect(edge2?.relationship).toBe('uses')
    })

    it('generates uses edges from external.uses', () => {
      // external-n8n-sync uses integration-zendesk
      const edge = commandViewData.edges.find(
        (e) => e.source === 'external-n8n-sync' && e.target === 'integration-zendesk'
      )
      expect(edge).toBeDefined()
      expect(edge?.relationship).toBe('uses')
    })
  })

  // ============================================================================
  // Serialization Roundtrip Tests
  // ============================================================================

  describe('Serialization Roundtrip', () => {
    let registry: ResourceRegistry

    beforeAll(() => {
      const testOrg = createTestOrganization()
      registry = new ResourceRegistry({ 'test-org': testOrg })
    })

    it('serialized data preserves all ResourceDefinition fields', () => {
      const resourceList = registry.getResourceList('test-org')

      for (const workflow of resourceList.workflows) {
        expect(workflow.resourceId).toBeDefined()
        expect(workflow.name).toBeDefined()
        expect(workflow.description).toBeDefined()
        expect(workflow.version).toBeDefined()
        expect(workflow.type).toBe('workflow')
        expect(workflow.status).toBeDefined()
      }

      for (const agent of resourceList.agents) {
        expect(agent.resourceId).toBeDefined()
        expect(agent.name).toBeDefined()
        expect(agent.description).toBeDefined()
        expect(agent.version).toBeDefined()
        expect(agent.type).toBe('agent')
        expect(agent.status).toBeDefined()
      }
    })

    it('command view workflows have resourceId, version, type', () => {
      const commandViewData = registry.getCommandViewData('test-org')

      expect(commandViewData.workflows.length).toBeGreaterThan(0)
      for (const workflow of commandViewData.workflows) {
        expect(workflow.resourceId).toBeDefined()
        expect(workflow.version).toBeDefined()
        expect(workflow.type).toBe('workflow')
      }
    })

    it('command view agents have resourceId, version, type', () => {
      const commandViewData = registry.getCommandViewData('test-org')

      expect(commandViewData.agents.length).toBeGreaterThan(0)
      for (const agent of commandViewData.agents) {
        expect(agent.resourceId).toBeDefined()
        expect(agent.version).toBeDefined()
        expect(agent.type).toBe('agent')
      }
    })

    it('command view data includes all node types', () => {
      const commandViewData = registry.getCommandViewData('test-org')

      expect(commandViewData.workflows.length).toBeGreaterThan(0)
      expect(commandViewData.agents.length).toBeGreaterThan(0)
      expect(commandViewData.triggers.length).toBeGreaterThan(0)
      expect(commandViewData.integrations.length).toBeGreaterThan(0)
      expect(commandViewData.externalResources.length).toBeGreaterThan(0)
      expect(commandViewData.humanCheckpoints.length).toBeGreaterThan(0)
    })

    it('command view edges reference valid node resourceIds', () => {
      const commandViewData = registry.getCommandViewData('test-org')

      // Collect all valid node IDs
      const validNodeIds = new Set([
        ...commandViewData.workflows.map((w) => w.resourceId),
        ...commandViewData.agents.map((a) => a.resourceId),
        ...commandViewData.triggers.map((t) => t.resourceId),
        ...commandViewData.integrations.map((i) => i.resourceId),
        ...commandViewData.externalResources.map((e) => e.resourceId),
        ...commandViewData.humanCheckpoints.map((h) => h.resourceId)
      ])

      // Verify all edges reference valid nodes
      for (const edge of commandViewData.edges) {
        expect(validNodeIds.has(edge.source)).toBe(true)
        expect(validNodeIds.has(edge.target)).toBe(true)
      }
    })

    it('serialized definitions match original config', () => {
      const workflowDef = registry.getSerializedDefinition('test-org', 'order-workflow')
      expect(workflowDef).toBeDefined()
      expect(workflowDef?.config.resourceId).toBe('order-workflow')
      expect(workflowDef?.config.name).toBe('Workflow order-workflow')
      expect(workflowDef?.config.type).toBe('workflow')

      const agentDef = registry.getSerializedDefinition('test-org', 'order-agent')
      expect(agentDef).toBeDefined()
      expect(agentDef?.config.resourceId).toBe('order-agent')
      expect(agentDef?.config.name).toBe('Agent order-agent')
      expect(agentDef?.config.type).toBe('agent')
    })
  })

  // ============================================================================
  // Validation Integration Tests
  // ============================================================================

  describe('Validation Integration', () => {
    it('throws for trigger triggering non-existent resource', () => {
      const invalidOrg: DeploymentSpec = {
        workflows: [createMockWorkflow('valid-workflow')],
        triggers: [
          {
            resourceId: 'trigger-invalid',
            type: 'trigger',
            triggerType: 'webhook',
            version: '1.0.0',
            name: 'Invalid Trigger',
            description: 'Triggers non-existent workflow',
            status: 'dev'
          }
        ],
        relationships: {
          'trigger-invalid': {
            triggers: { workflows: ['non-existent-workflow'] }
          }
        }
      }

      expect(() => {
        new ResourceRegistry({ 'test-org': invalidOrg })
      }).toThrow()
      expect(() => {
        new ResourceRegistry({ 'test-org': invalidOrg })
      }).toThrow('non-existent-workflow')
    })

    it('throws for external resource with conflicting ID', () => {
      const invalidOrg: DeploymentSpec = {
        workflows: [createMockWorkflow('conflict-id')],
        externalResources: [
          {
            resourceId: 'conflict-id', // Same as workflow
            type: 'external',
            version: '1.0.0',
            platform: 'n8n',
            name: 'Conflicting External',
            description: 'Has same ID as workflow',
            status: 'dev'
          }
        ]
      }

      expect(() => {
        new ResourceRegistry({ 'test-org': invalidOrg })
      }).toThrow("External resource ID 'conflict-id' conflicts with internal resource ID")
    })

    it('throws for human checkpoint with conflicting ID', () => {
      const invalidOrg: DeploymentSpec = {
        workflows: [createMockWorkflow('conflict-id')], // Changed to workflow
        humanCheckpoints: [
          {
            resourceId: 'conflict-id', // Same as workflow
            type: 'human',
            version: '1.0.0',
            name: 'Conflicting Checkpoint',
            description: 'Has same ID as workflow',
            status: 'dev'
          }
        ]
      }

      expect(() => {
        new ResourceRegistry({ 'test-org': invalidOrg })
      }).toThrow("Human checkpoint ID 'conflict-id' conflicts with internal resource ID")
    })

    it('throws for relationship to non-existent integration', () => {
      const invalidOrg: DeploymentSpec = {
        agents: [createMockAgent('test-agent')],
        relationships: {
          'test-agent': {
            uses: { integrations: ['non-existent-integration'] }
          }
        }
      }

      expect(() => {
        new ResourceRegistry({ 'test-org': invalidOrg })
      }).toThrow()
      expect(() => {
        new ResourceRegistry({ 'test-org': invalidOrg })
      }).toThrow('non-existent-integration')
    })

    it('validates relationship graph integrity', () => {
      const invalidOrg: DeploymentSpec = {
        workflows: [createMockWorkflow('workflow-1')],
        relationships: {
          'workflow-1': {
            triggers: { workflows: ['non-existent-workflow-2'] }
          }
        }
      }

      expect(() => {
        new ResourceRegistry({ 'test-org': invalidOrg })
      }).toThrow()
    })

    it('allows valid relationships without errors', () => {
      const validOrg: DeploymentSpec = {
        workflows: [createMockWorkflow('workflow-1'), createMockWorkflow('workflow-2')],
        agents: [createMockAgent('agent-1')],
        integrations: [
          {
            resourceId: 'integration-1',
            type: 'integration',
            version: '1.0.0',
            status: 'dev',
            provider: 'webhook',
            credentialName: 'webhook-cred',
            name: 'Webhook Integration',
            description: 'Test webhook'
          }
        ],
        relationships: {
          'workflow-1': {
            triggers: { workflows: ['workflow-2'], agents: ['agent-1'] },
            uses: { integrations: ['integration-1'] }
          }
        }
      }

      expect(() => {
        new ResourceRegistry({ 'test-org': validOrg })
      }).not.toThrow()
    })
  })

  // ============================================================================
  // Multi-Organization Isolation Tests
  // ============================================================================

  describe('Multi-Organization Isolation', () => {
    it('resources from different orgs are isolated', () => {
      const org1: DeploymentSpec = {
        workflows: [createMockWorkflow('workflow-org1')],
        agents: [createMockAgent('agent-org1')]
      }

      const org2: DeploymentSpec = {
        workflows: [createMockWorkflow('workflow-org2')],
        agents: [createMockAgent('agent-org2')]
      }

      const registry = new ResourceRegistry({
        org1,
        org2
      })

      // Org1 resources
      expect(registry.getResourceDefinition('org1', 'workflow-org1')).toBeDefined()
      expect(registry.getResourceDefinition('org1', 'agent-org1')).toBeDefined()
      expect(registry.getResourceDefinition('org1', 'workflow-org2')).toBeNull()
      expect(registry.getResourceDefinition('org1', 'agent-org2')).toBeNull()

      // Org2 resources
      expect(registry.getResourceDefinition('org2', 'workflow-org2')).toBeDefined()
      expect(registry.getResourceDefinition('org2', 'agent-org2')).toBeDefined()
      expect(registry.getResourceDefinition('org2', 'workflow-org1')).toBeNull()
      expect(registry.getResourceDefinition('org2', 'agent-org1')).toBeNull()
    })

    it('triggers can only reference resources in same org', () => {
      const org1: DeploymentSpec = {
        workflows: [createMockWorkflow('workflow-org1')],
        triggers: [
          {
            resourceId: 'trigger-org1',
            type: 'trigger',
            triggerType: 'manual',
            version: '1.0.0',
            name: 'Org1 Trigger',
            description: 'Triggers workflow in org2 (invalid)',
            status: 'dev'
          }
        ],
        relationships: {
          'trigger-org1': {
            triggers: { workflows: ['workflow-org2'] } // References org2 workflow - should fail
          }
        }
      }

      const org2: DeploymentSpec = {
        workflows: [createMockWorkflow('workflow-org2')]
      }

      expect(() => {
        new ResourceRegistry({ org1, org2 })
      }).toThrow('workflow-org2')
    })

    it('command view data is organization-specific', () => {
      // Create different orgs with different resource IDs
      const org1: DeploymentSpec = {
        workflows: [createMockWorkflow('org1-workflow')],
        agents: [createMockAgent('org1-agent')]
      }

      const org2: DeploymentSpec = {
        workflows: [createMockWorkflow('org2-workflow')],
        agents: [createMockAgent('org2-agent')]
      }

      const registry = new ResourceRegistry({ org1, org2 })

      const org1Data = registry.getCommandViewData('org1')
      const org2Data = registry.getCommandViewData('org2')

      // Both orgs should have same number of resources
      // but data should be independent instances
      expect(org1Data).not.toBe(org2Data)
      expect(org1Data.workflows.length).toBe(1)
      expect(org2Data.workflows.length).toBe(1)

      // Verify isolation - org1 nodes should not appear in org2 data
      const org1NodeIds = new Set([
        ...org1Data.workflows.map((w) => w.resourceId),
        ...org1Data.agents.map((a) => a.resourceId)
      ])

      const org2NodeIds = new Set([
        ...org2Data.workflows.map((w) => w.resourceId),
        ...org2Data.agents.map((a) => a.resourceId)
      ])

      // Verify no overlap in resource IDs
      for (const nodeId of org1NodeIds) {
        expect(org2NodeIds.has(nodeId)).toBe(false)
      }
      for (const nodeId of org2NodeIds) {
        expect(org1NodeIds.has(nodeId)).toBe(false)
      }

      // Verify edges reference only their own org's nodes
      for (const edge of org1Data.edges) {
        // org1 edges should only reference org1 nodes
        expect(
          org1NodeIds.has(edge.source) ||
            org1Data.triggers.some((t) => t.resourceId === edge.source) ||
            org1Data.integrations.some((i) => i.resourceId === edge.source)
        ).toBe(true)
        expect(
          org1NodeIds.has(edge.target) ||
            org1Data.triggers.some((t) => t.resourceId === edge.target) ||
            org1Data.integrations.some((i) => i.resourceId === edge.target)
        ).toBe(true)
      }

      for (const edge of org2Data.edges) {
        // org2 edges should not reference org1 nodes
        expect(org1NodeIds.has(edge.source)).toBe(false)
        expect(org1NodeIds.has(edge.target)).toBe(false)
      }
    })

    it('allows same resourceId across different organizations', () => {
      const org1: DeploymentSpec = {
        workflows: [createMockWorkflow('shared-id')]
      }

      const org2: DeploymentSpec = {
        workflows: [createMockWorkflow('shared-id')]
      }

      expect(() => {
        new ResourceRegistry({ org1, org2 })
      }).not.toThrow()

      const registry = new ResourceRegistry({ org1, org2 })

      const org1Resource = registry.getResourceDefinition('org1', 'shared-id')
      const org2Resource = registry.getResourceDefinition('org2', 'shared-id')

      expect(org1Resource).toBeDefined()
      expect(org2Resource).toBeDefined()
      expect(org1Resource).not.toBe(org2Resource) // Different instances
    })
  })

  // ============================================================================
  // Runtime Registration Relationship Tests
  // ============================================================================

  describe('Runtime Registration Relationships', () => {
    const remoteConfig = {
      storagePath: 'test-org-id/test-deploy-id/bundle.js',
      deploymentId: 'deploy-123'
    }

    it('registerOrganization merges relationships from stubs into existing org', () => {
      // Start with a static org that has a workflow and relationships
      const staticOrg: DeploymentSpec = {
        workflows: [createMockWorkflow('static-workflow')],
        agents: [createMockAgent('static-agent')],
        integrations: [
          {
            resourceId: 'integration-crm',
            type: 'integration',
            version: '1.0.0',
            status: 'dev',
            provider: 'crm',
            credentialName: 'crm-cred',
            name: 'CRM',
            description: 'CRM integration'
          }
        ],
        relationships: {
          'static-workflow': {
            triggers: { agents: ['static-agent'] }
          }
        }
      }

      const registry = new ResourceRegistry({ 'test-org': staticOrg })

      // Deploy stubs with their own relationships
      const stubs: DeploymentSpec = {
        workflows: [createMockWorkflow('remote-workflow')],
        integrations: [
          {
            resourceId: 'integration-crm',
            type: 'integration',
            version: '1.0.0',
            status: 'dev',
            provider: 'crm',
            credentialName: 'crm-cred',
            name: 'CRM',
            description: 'CRM integration'
          }
        ],
        relationships: {
          'remote-workflow': {
            uses: { integrations: ['integration-crm'] }
          }
        }
      }

      registry.registerOrganization('test-org', stubs, remoteConfig)

      // Both static and remote relationships should exist
      const relationships = registry.getRelationships('test-org')
      expect(relationships).toBeDefined()
      expect(relationships!['static-workflow']).toBeDefined()
      expect(relationships!['static-workflow'].triggers?.agents).toContain('static-agent')
      expect(relationships!['remote-workflow']).toBeDefined()
      expect(relationships!['remote-workflow'].uses?.integrations).toContain('integration-crm')
    })

    it('unregisterOrganization removes remote resource relationships, preserves static ones', () => {
      const staticOrg: DeploymentSpec = {
        workflows: [createMockWorkflow('static-workflow')],
        agents: [createMockAgent('static-agent')],
        relationships: {
          'static-workflow': {
            triggers: { agents: ['static-agent'] }
          }
        }
      }

      const registry = new ResourceRegistry({ 'test-org': staticOrg })

      // Register remote resources with relationships
      const stubs: DeploymentSpec = {
        workflows: [createMockWorkflow('remote-workflow')],
        relationships: {
          'remote-workflow': {
            triggers: { agents: ['static-agent'] }
          }
        }
      }

      registry.registerOrganization('test-org', stubs, remoteConfig)

      // Verify both exist
      expect(registry.getRelationships('test-org')!['remote-workflow']).toBeDefined()
      expect(registry.getRelationships('test-org')!['static-workflow']).toBeDefined()

      // Unregister remote resources
      registry.unregisterOrganization('test-org')

      // Static relationships preserved, remote relationships removed
      const relationships = registry.getRelationships('test-org')
      expect(relationships).toBeDefined()
      expect(relationships!['static-workflow']).toBeDefined()
      expect(relationships!['remote-workflow']).toBeUndefined()
    })

    it('getCommandViewData returns correct edges after registering with relationships', () => {
      const staticOrg: DeploymentSpec = {
        workflows: [createMockWorkflow('static-workflow')],
        agents: [createMockAgent('static-agent')],
        integrations: [
          {
            resourceId: 'integration-crm',
            type: 'integration',
            version: '1.0.0',
            status: 'dev',
            provider: 'crm',
            credentialName: 'crm-cred',
            name: 'CRM',
            description: 'CRM integration'
          }
        ]
      }

      const registry = new ResourceRegistry({ 'test-org': staticOrg })

      // No relationship edges before registration
      const beforeData = registry.getCommandViewData('test-org')
      const beforeEdges = beforeData.edges.filter(
        (e) => e.source === 'remote-workflow' || e.target === 'remote-workflow'
      )
      expect(beforeEdges).toHaveLength(0)

      // Register remote stubs with relationships
      const stubs: DeploymentSpec = {
        workflows: [createMockWorkflow('remote-workflow')],
        integrations: [
          {
            resourceId: 'integration-crm',
            type: 'integration',
            version: '1.0.0',
            status: 'dev',
            provider: 'crm',
            credentialName: 'crm-cred',
            name: 'CRM',
            description: 'CRM integration'
          }
        ],
        relationships: {
          'remote-workflow': {
            triggers: { workflows: ['static-workflow'] },
            uses: { integrations: ['integration-crm'] }
          }
        }
      }

      registry.registerOrganization('test-org', stubs, remoteConfig)

      // Command View should now include edges from remote relationships
      const afterData = registry.getCommandViewData('test-org')

      const triggersEdge = afterData.edges.find((e) => e.source === 'remote-workflow' && e.target === 'static-workflow')
      expect(triggersEdge).toBeDefined()
      expect(triggersEdge?.relationship).toBe('triggers')

      const usesEdge = afterData.edges.find((e) => e.source === 'remote-workflow' && e.target === 'integration-crm')
      expect(usesEdge).toBeDefined()
      expect(usesEdge?.relationship).toBe('uses')
    })
  })
})
