/**
 * @fileoverview V3 Spec Smoke Test
 * @description Verify that V3 type definitions and constants can be imported and used normally
 */

import { describe, it, expect, beforeEach } from 'vitest';

// ==================== Domain Types ====================
import {
  // JSON types
  type JsonValue,
  type JsonObject,
  type UnixMillis,

  // ID types
  type FlowId,
  type NodeId,
  type RunId,
  EDGE_LABELS,

  // Error types
  RR_ERROR_CODES,
  type RRError,
  createRRError,

  // Policy types
  type TimeoutPolicy,
  type RetryPolicy,
  type OnErrorPolicy,
  type NodePolicy,
  mergeNodePolicy,

  // Variable types
  type PersistentVariableName,
  isPersistentVariable,
  parseVariablePointer,

  // Flow types
  FLOW_SCHEMA_VERSION,
  type FlowV3,
  type NodeV3,
  type EdgeV3,
  findNodeById,

  // Event types
  type RunEvent,
  type RunStatus,
  type Unsubscribe,
  RUN_SCHEMA_VERSION,
  type RunRecordV3,
  isTerminalStatus,
  isActiveStatus,

  // Debug types
  type DebuggerState,
  type DebuggerCommand,
  createInitialDebuggerState,

  // Trigger types
  type TriggerKind,
  type TriggerSpec,
  isTriggerEnabled,
} from '@/entrypoints/background/record-replay-v3';

describe('V3 Domain Types', () => {
  describe('Constants', () => {
    it('should export EDGE_LABELS', () => {
      expect(EDGE_LABELS).toBeDefined();
      expect(EDGE_LABELS.DEFAULT).toBe('default');
      expect(EDGE_LABELS.ON_ERROR).toBe('onError');
      expect(EDGE_LABELS.TRUE).toBe('true');
      expect(EDGE_LABELS.FALSE).toBe('false');
    });

    it('should export RR_ERROR_CODES', () => {
      expect(RR_ERROR_CODES).toBeDefined();
      expect(RR_ERROR_CODES.TIMEOUT).toBe('TIMEOUT');
      expect(RR_ERROR_CODES.VALIDATION_ERROR).toBe('VALIDATION_ERROR');
      expect(RR_ERROR_CODES.DAG_CYCLE).toBe('DAG_CYCLE');
    });

    it('should export schema versions', () => {
      expect(FLOW_SCHEMA_VERSION).toBe(3);
      expect(RUN_SCHEMA_VERSION).toBe(3);
    });
  });

  describe('Error utilities', () => {
    it('should create RRError', () => {
      const error = createRRError(RR_ERROR_CODES.TIMEOUT, 'Operation timed out', {
        retryable: true,
        data: { timeout: 5000 },
      });

      expect(error.code).toBe('TIMEOUT');
      expect(error.message).toBe('Operation timed out');
      expect(error.retryable).toBe(true);
      expect(error.data).toEqual({ timeout: 5000 });
    });

    it('should support error chaining', () => {
      const cause = createRRError(RR_ERROR_CODES.NETWORK_REQUEST_FAILED, 'Network error');
      const error = createRRError(RR_ERROR_CODES.TOOL_ERROR, 'Tool failed', { cause });

      expect(error.cause).toBeDefined();
      expect(error.cause?.code).toBe('NETWORK_REQUEST_FAILED');
    });
  });

  describe('Policy utilities', () => {
    it('should merge node policies', () => {
      const flowDefault: NodePolicy = {
        timeout: { ms: 30000 },
        retry: { retries: 3, intervalMs: 1000 },
      };

      const nodePolicy: NodePolicy = {
        timeout: { ms: 60000 },
      };

      const merged = mergeNodePolicy(flowDefault, nodePolicy);

      expect(merged.timeout?.ms).toBe(60000); // Node overrides
      expect(merged.retry?.retries).toBe(3); // Flow default
    });

    it('should handle undefined policies', () => {
      expect(mergeNodePolicy(undefined, undefined)).toEqual({});
      expect(mergeNodePolicy({ timeout: { ms: 5000 } }, undefined)).toEqual({
        timeout: { ms: 5000 },
      });
    });
  });

  describe('Variable utilities', () => {
    it('should detect persistent variables', () => {
      expect(isPersistentVariable('$user')).toBe(true);
      expect(isPersistentVariable('$config.theme')).toBe(true);
      expect(isPersistentVariable('normalVar')).toBe(false);
    });

    it('should parse variable pointers', () => {
      const ptr1 = parseVariablePointer('$user.name');
      expect(ptr1?.scope).toBe('persistent');
      expect(ptr1?.name).toBe('$user');
      expect(ptr1?.path).toEqual(['name']);

      const ptr2 = parseVariablePointer('localVar');
      expect(ptr2?.scope).toBe('run');
      expect(ptr2?.name).toBe('localVar');
    });
  });

  describe('Flow utilities', () => {
    const mockFlow: FlowV3 = {
      schemaVersion: FLOW_SCHEMA_VERSION,
      id: 'flow-1',
      name: 'Test Flow',
      createdAt: new Date().toISOString(),
      updatedAt: new Date().toISOString(),
      entryNodeId: 'node-1',
      nodes: [
        { id: 'node-1', kind: 'click', config: {} },
        { id: 'node-2', kind: 'fill', config: {} },
      ],
      edges: [{ id: 'edge-1', from: 'node-1', to: 'node-2' }],
    };

    it('should find node by id', () => {
      const node = findNodeById(mockFlow, 'node-1');
      expect(node).toBeDefined();
      expect(node?.kind).toBe('click');

      expect(findNodeById(mockFlow, 'non-existent')).toBeUndefined();
    });
  });

  describe('Event utilities', () => {
    it('should check terminal status', () => {
      expect(isTerminalStatus('succeeded')).toBe(true);
      expect(isTerminalStatus('failed')).toBe(true);
      expect(isTerminalStatus('canceled')).toBe(true);
      expect(isTerminalStatus('running')).toBe(false);
      expect(isTerminalStatus('queued')).toBe(false);
    });

    it('should check active status', () => {
      expect(isActiveStatus('running')).toBe(true);
      expect(isActiveStatus('paused')).toBe(true);
      expect(isActiveStatus('succeeded')).toBe(false);
      expect(isActiveStatus('queued')).toBe(false);
    });
  });

  describe('Debug utilities', () => {
    it('should create initial debugger state', () => {
      const state = createInitialDebuggerState('run-1');

      expect(state.runId).toBe('run-1');
      expect(state.status).toBe('detached');
      expect(state.execution).toBe('running');
      expect(state.breakpoints).toEqual([]);
      expect(state.stepMode).toBe('none');
    });
  });

  describe('Trigger utilities', () => {
    it('should check trigger enabled', () => {
      const enabledTrigger: TriggerSpec = {
        id: 'trigger-1',
        kind: 'manual',
        enabled: true,
        flowId: 'flow-1',
      };

      const disabledTrigger: TriggerSpec = {
        id: 'trigger-2',
        kind: 'manual',
        enabled: false,
        flowId: 'flow-1',
      };

      expect(isTriggerEnabled(enabledTrigger)).toBe(true);
      expect(isTriggerEnabled(disabledTrigger)).toBe(false);
    });
  });
});

// ==================== Engine Types ====================
import type {
  ExecutionKernel,
  RunStartRequest,
} from '@/entrypoints/background/record-replay-v3/engine/kernel/kernel';
import { createNotImplementedKernel } from '@/entrypoints/background/record-replay-v3/engine/kernel/kernel';
import type { RunQueue, RunQueueItem } from '@/entrypoints/background/record-replay-v3/engine/queue/queue';
import {
  DEFAULT_QUEUE_CONFIG,
  createNotImplementedQueue,
} from '@/entrypoints/background/record-replay-v3/engine/queue/queue';
import type { NodeDefinition } from '@/entrypoints/background/record-replay-v3/engine/plugins/types';
import {
  PluginRegistry,
  getPluginRegistry,
  resetPluginRegistry,
} from '@/entrypoints/background/record-replay-v3/engine/plugins/registry';
import { InMemoryEventsBus } from '@/entrypoints/background/record-replay-v3/engine/transport/events-bus';
import {
  RR_V3_PORT_NAME,
  createRpcRequest,
} from '@/entrypoints/background/record-replay-v3/engine/transport/rpc';
import type { RpcMessage } from '@/entrypoints/background/record-replay-v3/engine/transport/rpc';

describe('V3 Engine Types', () => {
  describe('Kernel', () => {
    it('should create not-implemented kernel', () => {
      const kernel = createNotImplementedKernel();
      expect(kernel).toBeDefined();
      expect(() => kernel.onEvent(() => {})).toThrow('not implemented');
    });
  });

  describe('Queue', () => {
    it('should export default queue config', () => {
      expect(DEFAULT_QUEUE_CONFIG).toBeDefined();
      expect(DEFAULT_QUEUE_CONFIG.maxParallelRuns).toBe(3);
      expect(DEFAULT_QUEUE_CONFIG.leaseTtlMs).toBe(15000);
    });

    it('should create not-implemented queue', () => {
      const queue = createNotImplementedQueue();
      expect(queue).toBeDefined();
    });
  });

  describe('Plugin Registry', () => {
    beforeEach(() => {
      resetPluginRegistry();
    });

    it('should get global registry', () => {
      const registry = getPluginRegistry();
      expect(registry).toBeDefined();
      expect(registry.listNodeKinds()).toEqual([]);
    });

    it('should register and retrieve nodes', () => {
      const registry = getPluginRegistry();

      const mockNodeDef: NodeDefinition = {
        kind: 'test-node',
        schema: { parse: (x: unknown) => x } as NodeDefinition['schema'],
        execute: async () => ({ status: 'succeeded' }),
      };

      registry.registerNode(mockNodeDef);
      expect(registry.hasNode('test-node')).toBe(true);
      expect(registry.getNode('test-node')).toBe(mockNodeDef);
    });
  });

  describe('Transport', () => {
    it('should export port name', () => {
      expect(RR_V3_PORT_NAME).toBe('rr_v3');
    });

    it('should create RPC request', () => {
      const req = createRpcRequest('rr_v3.listRuns', { limit: 10 });

      expect(req.type).toBe('rr_v3.request');
      expect(req.method).toBe('rr_v3.listRuns');
      expect(req.params).toEqual({ limit: 10 });
      expect(req.requestId).toBeDefined();
    });
  });

  describe('EventsBus (InMemory)', () => {
    it('should append and list events', async () => {
      const bus = new InMemoryEventsBus();

      const event = await bus.append({
        runId: 'run-1',
        type: 'run.started',
        flowId: 'flow-1',
        tabId: 1,
      });

      expect(event.seq).toBe(1);
      expect(event.ts).toBeDefined();

      const events = await bus.list({ runId: 'run-1' });
      expect(events).toHaveLength(1);
      expect(events[0].type).toBe('run.started');
    });

    it('should support subscriptions', async () => {
      const bus = new InMemoryEventsBus();
      const received: RunEvent[] = [];

      const unsub = bus.subscribe((event) => received.push(event));

      await bus.append({ runId: 'run-1', type: 'run.queued', flowId: 'flow-1' });

      expect(received).toHaveLength(1);

      unsub();

      await bus.append({ runId: 'run-1', type: 'run.started', flowId: 'flow-1', tabId: 1 });

      // Should not receive after unsubscribe
      expect(received).toHaveLength(1);
    });
  });
});

// ==================== Storage Types ====================
import {
  RR_V3_DB_NAME,
  RR_V3_DB_VERSION,
  RR_V3_STORES,
} from '@/entrypoints/background/record-replay-v3/storage/db';

describe('V3 Storage Constants', () => {
  it('should export database constants', () => {
    expect(RR_V3_DB_NAME).toBe('rr_v3');
    expect(RR_V3_DB_VERSION).toBe(2);
  });

  it('should export store names', () => {
    expect(RR_V3_STORES.FLOWS).toBe('flows');
    expect(RR_V3_STORES.RUNS).toBe('runs');
    expect(RR_V3_STORES.EVENTS).toBe('events');
    expect(RR_V3_STORES.QUEUE).toBe('queue');
    expect(RR_V3_STORES.PERSISTENT_VARS).toBe('persistent_vars');
    expect(RR_V3_STORES.TRIGGERS).toBe('triggers');
    expect(RR_V3_STORES.ARTIFACTS).toBe('artifacts');
  });
});

// ==================== Version ====================
import { RR_V3_VERSION } from '@/entrypoints/background/record-replay-v3';

describe('V3 Version', () => {
  it('should export version info', () => {
    expect(RR_V3_VERSION).toBe('3.0.0');
  });
});
