// @lifecycle canonical - Unit tests for PendingConfirmationTracker.
/**
 * PendingConfirmationTracker Unit Tests
 *
 * Tests the "re-run to approve" workflow for script tools:
 * - Recording pending confirmations
 * - Auto-approving on re-run with matching inputs
 * - Expiration handling
 * - Input hash matching
 */

import {
  PendingConfirmationTracker,
  getDefaultPendingConfirmationTracker,
  resetDefaultPendingConfirmationTracker,
} from '../../../../src/modules/automation/execution/pending-confirmation-tracker.js';

describe('PendingConfirmationTracker', () => {
  let tracker: PendingConfirmationTracker;

  beforeEach(() => {
    tracker = new PendingConfirmationTracker({ debug: false });
  });

  afterEach(() => {
    resetDefaultPendingConfirmationTracker();
  });

  describe('recordPending', () => {
    it('should record a pending confirmation', () => {
      tracker.recordPending('test_prompt', 'tool1', { key: 'value' });

      expect(tracker.hasPending('test_prompt', 'tool1')).toBe(true);
      expect(tracker.size).toBe(1);
    });

    it('should overwrite existing pending for same prompt+tool', () => {
      tracker.recordPending('test_prompt', 'tool1', { key: 'value1' });
      tracker.recordPending('test_prompt', 'tool1', { key: 'value2' });

      expect(tracker.size).toBe(1);
    });

    it('should track multiple tools for same prompt', () => {
      tracker.recordPending('test_prompt', 'tool1', { key: 'value1' });
      tracker.recordPending('test_prompt', 'tool2', { key: 'value2' });

      expect(tracker.hasPending('test_prompt', 'tool1')).toBe(true);
      expect(tracker.hasPending('test_prompt', 'tool2')).toBe(true);
      expect(tracker.size).toBe(2);
    });
  });

  describe('checkAndClearPending', () => {
    it('should return true and clear pending for matching inputs', () => {
      const inputs = { name: 'test', value: 123 };
      tracker.recordPending('test_prompt', 'tool1', inputs);

      const result = tracker.checkAndClearPending('test_prompt', 'tool1', inputs);

      expect(result).toBe(true);
      expect(tracker.hasPending('test_prompt', 'tool1')).toBe(false);
    });

    it('should return false for non-existent pending', () => {
      const result = tracker.checkAndClearPending('test_prompt', 'tool1', {});

      expect(result).toBe(false);
    });

    it('should return false for mismatched inputs', () => {
      tracker.recordPending('test_prompt', 'tool1', { key: 'value1' });

      const result = tracker.checkAndClearPending('test_prompt', 'tool1', { key: 'different' });

      expect(result).toBe(false);
      // Should still be pending (not cleared because inputs didn't match)
      expect(tracker.hasPending('test_prompt', 'tool1')).toBe(true);
    });

    it('should match inputs regardless of key order', () => {
      const inputs1 = { a: 1, b: 2, c: 3 };
      const inputs2 = { c: 3, a: 1, b: 2 }; // Different order

      tracker.recordPending('test_prompt', 'tool1', inputs1);
      const result = tracker.checkAndClearPending('test_prompt', 'tool1', inputs2);

      expect(result).toBe(true);
    });

    it('should match nested objects with different key order', () => {
      const inputs1 = { outer: { a: 1, b: 2 } };
      const inputs2 = { outer: { b: 2, a: 1 } };

      tracker.recordPending('test_prompt', 'tool1', inputs1);
      const result = tracker.checkAndClearPending('test_prompt', 'tool1', inputs2);

      expect(result).toBe(true);
    });
  });

  describe('hasPending', () => {
    it('should return false for non-existent pending', () => {
      expect(tracker.hasPending('test_prompt', 'tool1')).toBe(false);
    });

    it('should return true for existing pending', () => {
      tracker.recordPending('test_prompt', 'tool1', {});
      expect(tracker.hasPending('test_prompt', 'tool1')).toBe(true);
    });
  });

  describe('expiration', () => {
    it('should return false for expired pending in checkAndClearPending', () => {
      // Create tracker with 1ms expiration for testing
      const shortTracker = new PendingConfirmationTracker({ expirationMs: 1 });
      shortTracker.recordPending('test_prompt', 'tool1', {});

      // Wait for expiration
      return new Promise<void>((resolve) => {
        setTimeout(() => {
          const result = shortTracker.checkAndClearPending('test_prompt', 'tool1', {});
          expect(result).toBe(false);
          resolve();
        }, 10);
      });
    });

    it('should return false for expired pending in hasPending', () => {
      const shortTracker = new PendingConfirmationTracker({ expirationMs: 1 });
      shortTracker.recordPending('test_prompt', 'tool1', {});

      return new Promise<void>((resolve) => {
        setTimeout(() => {
          expect(shortTracker.hasPending('test_prompt', 'tool1')).toBe(false);
          resolve();
        }, 10);
      });
    });
  });

  describe('clear', () => {
    it('should clear all pending confirmations', () => {
      tracker.recordPending('prompt1', 'tool1', {});
      tracker.recordPending('prompt2', 'tool2', {});

      tracker.clear();

      expect(tracker.size).toBe(0);
      expect(tracker.hasPending('prompt1', 'tool1')).toBe(false);
      expect(tracker.hasPending('prompt2', 'tool2')).toBe(false);
    });
  });

  describe('default instance management', () => {
    it('should return same instance on multiple calls', () => {
      const instance1 = getDefaultPendingConfirmationTracker();
      const instance2 = getDefaultPendingConfirmationTracker();

      expect(instance1).toBe(instance2);
    });

    it('should create new instance after reset', () => {
      const instance1 = getDefaultPendingConfirmationTracker();
      resetDefaultPendingConfirmationTracker();
      const instance2 = getDefaultPendingConfirmationTracker();

      expect(instance1).not.toBe(instance2);
    });
  });
});
