import { describe, it, expect } from 'vitest';
import type { IAutomationService, AutomationResult } from './automation-service';
import type { FlowParsed } from '../automation/flow.zod';
import type { ExecutionLog } from '../automation/execution.zod';

describe('Automation Service Contract', () => {
  it('should allow a minimal IAutomationService implementation with required methods', () => {
    const service: IAutomationService = {
      execute: async (_flowName, _context?) => ({ success: true }),
      listFlows: async () => [],
    };

    expect(typeof service.execute).toBe('function');
    expect(typeof service.listFlows).toBe('function');
  });

  it('should allow a full implementation with optional methods', () => {
    const service: IAutomationService = {
      execute: async () => ({ success: true }),
      listFlows: async () => [],
      registerFlow: (_name, _definition) => {},
      unregisterFlow: (_name) => {},
      getFlow: async (_name) => null,
      toggleFlow: async (_name, _enabled) => {},
      listRuns: async (_flowName, _options?) => [],
      getRun: async (_runId) => null,
    };

    expect(service.registerFlow).toBeDefined();
    expect(service.unregisterFlow).toBeDefined();
    expect(service.getFlow).toBeDefined();
    expect(service.toggleFlow).toBeDefined();
    expect(service.listRuns).toBeDefined();
    expect(service.getRun).toBeDefined();
  });

  it('should execute a flow successfully', async () => {
    const service: IAutomationService = {
      execute: async (flowName, context?): Promise<AutomationResult> => {
        return {
          success: true,
          output: { flowName, recordId: (context?.record as any)?.id },
          durationMs: 42,
        };
      },
      listFlows: async () => ['send_welcome_email', 'update_status'],
    };

    const result = await service.execute('send_welcome_email', {
      record: { id: 'rec-1', name: 'Alice' },
      object: 'contact',
      event: 'on_create',
    });

    expect(result.success).toBe(true);
    expect(result.output).toEqual({ flowName: 'send_welcome_email', recordId: 'rec-1' });
    expect(result.durationMs).toBe(42);
  });

  it('should handle execution failures', async () => {
    const service: IAutomationService = {
      execute: async () => ({
        success: false,
        error: 'Flow step 3 failed: timeout',
      }),
      listFlows: async () => [],
    };

    const result = await service.execute('broken_flow');
    expect(result.success).toBe(false);
    expect(result.error).toContain('timeout');
  });

  it('should list registered flows', async () => {
    const service: IAutomationService = {
      execute: async () => ({ success: true }),
      listFlows: async () => ['onboarding_flow', 'approval_flow', 'cleanup_flow'],
    };

    const flows = await service.listFlows();
    expect(flows).toHaveLength(3);
    expect(flows).toContain('approval_flow');
  });

  it('should return typed FlowParsed from getFlow', async () => {
    const mockFlow: FlowParsed = {
      name: 'approval_flow',
      label: 'Approval Flow',
      type: 'autolaunched',
      status: 'draft',
      version: 1,
      enabled: true,
      nodes: [
        { id: 'start', type: 'start', label: 'Start' },
        { id: 'end', type: 'end', label: 'End' },
      ],
      edges: [{ id: 'e1', source: 'start', target: 'end' }],
    };

    const service: IAutomationService = {
      execute: async () => ({ success: true }),
      listFlows: async () => ['approval_flow'],
      getFlow: async (name) => name === 'approval_flow' ? mockFlow : null,
    };

    const flow = await service.getFlow!('approval_flow');
    expect(flow).not.toBeNull();
    expect(flow!.name).toBe('approval_flow');
    expect(flow!.nodes).toHaveLength(2);

    const missing = await service.getFlow!('nonexistent');
    expect(missing).toBeNull();
  });

  it('should return typed ExecutionLog from listRuns and getRun', async () => {
    const mockRun: ExecutionLog = {
      id: 'exec_001',
      flowName: 'approval_flow',
      status: 'completed',
      trigger: { type: 'api' },
      steps: [{
        nodeId: 'start',
        nodeType: 'start',
        status: 'success',
        startedAt: '2026-02-01T10:00:00Z',
        durationMs: 1,
      }],
      startedAt: '2026-02-01T10:00:00Z',
      completedAt: '2026-02-01T10:00:01Z',
      durationMs: 1000,
    };

    const service: IAutomationService = {
      execute: async () => ({ success: true }),
      listFlows: async () => ['approval_flow'],
      listRuns: async (_flowName, _options?) => [mockRun],
      getRun: async (runId) => runId === 'exec_001' ? mockRun : null,
    };

    const runs = await service.listRuns!('approval_flow');
    expect(runs).toHaveLength(1);
    expect(runs[0].id).toBe('exec_001');
    expect(runs[0].status).toBe('completed');
    expect(runs[0].steps).toHaveLength(1);

    const run = await service.getRun!('exec_001');
    expect(run).not.toBeNull();
    expect(run!.flowName).toBe('approval_flow');
    expect(run!.durationMs).toBe(1000);

    const missingRun = await service.getRun!('nonexistent');
    expect(missingRun).toBeNull();
  });

  it('should support toggleFlow to enable/disable flows', async () => {
    let flowEnabled = true;

    const service: IAutomationService = {
      execute: async () => ({ success: true }),
      listFlows: async () => ['test_flow'],
      toggleFlow: async (_name, enabled) => { flowEnabled = enabled; },
    };

    await service.toggleFlow!('test_flow', false);
    expect(flowEnabled).toBe(false);

    await service.toggleFlow!('test_flow', true);
    expect(flowEnabled).toBe(true);
  });
});
