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

import {
  buildCapabilityBindingPayload,
  resolveCapabilityIssueIndex,
  sanitizeCapabilityOptions,
  sanitizeHitlConfig,
  shouldLoadMcpTools,
} from './skill-capability';

describe('skill capability payload', () => {
  it('only sends writable binding fields', () => {
    expect(
      buildCapabilityBindingPayload({
        capabilityType: 'MCP',
        enabled: true,
        executionMode: 'ASYNC',
        hitlConfigJson: {
          prompt: '  Continue?  ',
          token: 'must-not-leak',
        },
        id: 9,
        resolvedToolNames: ['server-only'],
        runtimeName: 'search',
        selectedToolNamesJson: ['query'],
        selectionMode: 'SELECTED',
        sortNo: 0,
        targetId: 12,
        targetLogicalRef: 'mcp:search',
        targetName: 'Search MCP',
        targetStatus: 'AVAILABLE',
        optionsJson: {
          headers: { Authorization: 'secret' },
          readOnly: true,
          retryCount: 2,
        },
      }),
    ).toEqual({
      capabilityType: 'MCP',
      enabled: true,
      executionMode: undefined,
      hitlConfigJson: { prompt: 'Continue?' },
      hitlEnabled: undefined,
      optionsJson: { readOnly: true, retryCount: 2 },
      runtimeName: 'search',
      selectedToolNamesJson: ['query'],
      selectionMode: 'SELECTED',
      sortNo: 0,
      targetId: 12,
      targetLogicalRef: 'mcp:search',
    });
  });

  it('normalizes non-MCP execution mode and drops MCP-only fields', () => {
    expect(
      buildCapabilityBindingPayload({
        capabilityType: 'WORKFLOW',
        enabled: true,
        runtimeName: 'review',
        selectedToolNamesJson: ['ignored'],
        selectionMode: 'SELECTED',
        targetId: 1,
      }),
    ).toMatchObject({
      executionMode: 'SYNC',
      selectedToolNamesJson: undefined,
      selectionMode: undefined,
    });
  });

  it('strictly whitelists scalar HITL and execution options', () => {
    expect(
      sanitizeHitlConfig({
        cancelLabel: 'Cancel',
        nested: { prompt: 'unsafe' },
        prompt: 'Approve this call?',
        secret: 'hidden',
      }),
    ).toEqual({ cancelLabel: 'Cancel', prompt: 'Approve this call?' });
    expect(
      sanitizeCapabilityOptions({
        async: false,
        credential: 'hidden',
        readOnly: true,
        retryCount: 1.9,
        timeoutMs: 5000,
      }),
    ).toEqual({
      async: false,
      readOnly: true,
      retryCount: 1,
      timeoutMs: 5000,
    });
  });

  it('locates a binding from backend validation paths', () => {
    expect(resolveCapabilityIssueIndex('capabilities[2].runtimeName')).toBe(2);
    expect(
      resolveCapabilityIssueIndex('skills[demo].capabilities[1].targetId'),
    ).toBe(1);
    expect(resolveCapabilityIssueIndex('SKILL.md')).toBeUndefined();
  });

  it('loads MCP tools only for a selected scope with a concrete target', () => {
    expect(shouldLoadMcpTools('MCP', 'ALL', 12)).toBe(false);
    expect(shouldLoadMcpTools('MCP', 'SELECTED')).toBe(false);
    expect(shouldLoadMcpTools('MCP', 'SELECTED', '')).toBe(false);
    expect(shouldLoadMcpTools('MCP', 'SELECTED', '   ')).toBe(false);
    expect(shouldLoadMcpTools('WORKFLOW', 'SELECTED', 12)).toBe(false);
    expect(shouldLoadMcpTools('PLUGIN_ITEM', 'SELECTED', 12)).toBe(false);
    expect(shouldLoadMcpTools('MCP', 'SELECTED', 12)).toBe(true);
  });
});
