import { describe, expect, test } from 'bun:test';

import {
  approvalPolicyRequiresToolCallApproval,
  approvalPolicyRequiresCheckpoint,
  normalizeApprovalPolicy,
  normalizePendingApproval,
  normalizePendingApprovalState,
  normalizeSessionApprovalSettings,
  dequeuePendingApprovalState,
  enqueuePendingApprovalState,
  listPendingApprovals,
  resolveEffectiveApprovalPolicy,
} from '@shared/domain/approval';

describe('approval helpers', () => {
  test('normalizes duplicate checkpoint rules and auto-approved tools into stable policy entries', () => {
    expect(normalizeApprovalPolicy({
      rules: [
        { kind: 'tool-call', agentIds: ['agent-1', ' agent-1 ', 'agent-2'] },
        { kind: 'tool-call', agentIds: ['agent-2', 'agent-3'] },
        { kind: 'final-response', agentIds: [] },
      ],
      autoApprovedToolNames: [' git.status ', 'git.status', 'lsp_ts_hover'],
    })).toEqual({
      rules: [
        { kind: 'tool-call', agentIds: ['agent-1', 'agent-2', 'agent-3'] },
        { kind: 'final-response' },
      ],
      autoApprovedToolNames: ['git.status', 'lsp_ts_hover'],
    });
  });

  test('matches approval requirements for all-agent and agent-specific rules', () => {
    const policy = normalizeApprovalPolicy({
      rules: [
        { kind: 'tool-call', agentIds: ['agent-1'] },
        { kind: 'final-response', agentIds: [] },
      ],
      autoApprovedToolNames: ['git.status'],
    });

    expect(approvalPolicyRequiresCheckpoint(policy, 'tool-call', 'agent-1')).toBe(true);
    expect(approvalPolicyRequiresCheckpoint(policy, 'tool-call', 'agent-2')).toBe(false);
    expect(approvalPolicyRequiresCheckpoint(policy, 'final-response', 'agent-2')).toBe(true);
    expect(approvalPolicyRequiresToolCallApproval(policy, 'agent-1', 'git.status')).toBe(false);
    expect(approvalPolicyRequiresToolCallApproval(policy, 'agent-1', 'git.diff')).toBe(true);
    expect(approvalPolicyRequiresToolCallApproval(policy, 'agent-2', 'git.diff')).toBe(false);
  });

  test('resolves session approval settings over pattern auto-approval defaults', () => {
    expect(resolveEffectiveApprovalPolicy(
      {
        rules: [{ kind: 'tool-call' }],
        autoApprovedToolNames: ['git.status'],
      },
      normalizeSessionApprovalSettings({
        autoApprovedToolNames: ['git.diff'],
      }),
    )).toEqual({
      rules: [{ kind: 'tool-call' }],
      autoApprovedToolNames: ['git.diff'],
    });

    expect(resolveEffectiveApprovalPolicy(
      {
        rules: [{ kind: 'tool-call' }],
        autoApprovedToolNames: ['git.status'],
      },
      normalizeSessionApprovalSettings({
        autoApprovedToolNames: [],
      }),
    )).toEqual({
      rules: [{ kind: 'tool-call' }],
    });
  });

  test('normalizes pending approvals with optional message previews', () => {
    expect(normalizePendingApproval({
      id: 'approval-1',
      kind: 'final-response',
      status: 'pending',
      requestedAt: '2026-03-24T10:00:00.000Z',
      title: 'Approve final response',
      messages: [
        {
          id: 'msg-1',
          authorName: 'Primary Agent',
          content: 'Draft answer',
        },
      ],
    })).toEqual({
      id: 'approval-1',
      kind: 'final-response',
      status: 'pending',
      requestedAt: '2026-03-24T10:00:00.000Z',
      title: 'Approve final response',
      messages: [
        {
          id: 'msg-1',
          authorName: 'Primary Agent',
          content: 'Draft answer',
        },
      ],
    });
  });

  test('normalizes legacy active approval plus queued approvals into a stable pending state', () => {
    expect(normalizePendingApprovalState({
      pendingApproval: {
        id: 'approval-1',
        kind: 'tool-call',
        status: 'pending',
        requestedAt: '2026-03-24T10:00:00.000Z',
        title: 'Approve tool access',
      },
      pendingApprovalQueue: [
        {
          id: 'approval-1',
          kind: 'tool-call',
          status: 'pending',
          requestedAt: '2026-03-24T10:00:00.000Z',
          title: 'Approve tool access',
        },
        {
          id: 'approval-2',
          kind: 'final-response',
          status: 'pending',
          requestedAt: '2026-03-24T10:01:00.000Z',
          title: 'Approve final response',
        },
        {
          id: 'approval-3',
          kind: 'tool-call',
          status: 'approved',
          requestedAt: '2026-03-24T10:02:00.000Z',
          resolvedAt: '2026-03-24T10:03:00.000Z',
          title: 'Already resolved',
        },
      ],
    })).toEqual({
      pendingApproval: {
        id: 'approval-1',
        kind: 'tool-call',
        status: 'pending',
        requestedAt: '2026-03-24T10:00:00.000Z',
        title: 'Approve tool access',
      },
      pendingApprovalQueue: [
        {
          id: 'approval-2',
          kind: 'final-response',
          status: 'pending',
          requestedAt: '2026-03-24T10:01:00.000Z',
          title: 'Approve final response',
        },
      ],
    });
  });

  test('enqueues and dequeues pending approvals while keeping the first approval active', () => {
    const state = enqueuePendingApprovalState(
      {
        pendingApproval: {
          id: 'approval-1',
          kind: 'tool-call',
          status: 'pending',
          requestedAt: '2026-03-24T10:00:00.000Z',
          title: 'Approve tool access',
        },
      },
      {
        id: 'approval-2',
        kind: 'final-response',
        status: 'pending',
        requestedAt: '2026-03-24T10:01:00.000Z',
        title: 'Approve final response',
      },
    );

    expect(listPendingApprovals(state).map((approval) => approval.id)).toEqual([
      'approval-1',
      'approval-2',
    ]);

    expect(dequeuePendingApprovalState(state, 'approval-1')).toEqual({
      pendingApproval: {
        id: 'approval-2',
        kind: 'final-response',
        status: 'pending',
        requestedAt: '2026-03-24T10:01:00.000Z',
        title: 'Approve final response',
      },
      pendingApprovalQueue: undefined,
    });
  });
});
