/**
 * RetryPolicy Tests — Verify retry logic for different error types.
 */

import { describe, it, expect, beforeEach } from 'vitest';
import { DefaultRetryPolicy, type AgentError } from './retry-policy.js';

describe('DefaultRetryPolicy', () => {
  let retryPolicy: DefaultRetryPolicy;

  beforeEach(() => {
    retryPolicy = new DefaultRetryPolicy();
  });

  describe('configuration', () => {
    it('should have correct max attempts', () => {
      expect(retryPolicy.maxAttempts).toBe(3);
    });

    it('should have exponential backoff delays', () => {
      expect(retryPolicy.backoffMs).toEqual([1000, 2000, 4000]);
    });
  });

  describe('shouldRetry', () => {
    it('should retry auth failures', () => {
      const error: AgentError = {
        type: 'auth_failure',
        message: 'Unauthorized',
        isTransient: true,
        requiresAccountSwitch: false,
        shouldPersistToDB: true
      };

      expect(retryPolicy.shouldRetry(error, 1)).toBe(true);
      expect(retryPolicy.shouldRetry(error, 2)).toBe(true);
      expect(retryPolicy.shouldRetry(error, 3)).toBe(false); // At max attempts
    });

    it('should not retry usage limit errors', () => {
      const error: AgentError = {
        type: 'usage_limit',
        message: 'Rate limit exceeded',
        isTransient: false,
        requiresAccountSwitch: true,
        shouldPersistToDB: true
      };

      expect(retryPolicy.shouldRetry(error, 1)).toBe(false);
      expect(retryPolicy.shouldRetry(error, 2)).toBe(false);
    });

    it('should retry missing signal errors', () => {
      const error: AgentError = {
        type: 'missing_signal',
        message: 'No signal.json found',
        isTransient: true,
        requiresAccountSwitch: false,
        shouldPersistToDB: false
      };

      expect(retryPolicy.shouldRetry(error, 1)).toBe(true);
      expect(retryPolicy.shouldRetry(error, 2)).toBe(true);
      expect(retryPolicy.shouldRetry(error, 3)).toBe(false); // At max attempts
    });

    it('should retry transient process crashes', () => {
      const error: AgentError = {
        type: 'process_crash',
        message: 'Process died',
        isTransient: true,
        requiresAccountSwitch: false,
        shouldPersistToDB: true
      };

      expect(retryPolicy.shouldRetry(error, 1)).toBe(true);
      expect(retryPolicy.shouldRetry(error, 2)).toBe(true);
    });

    it('should not retry non-transient process crashes', () => {
      const error: AgentError = {
        type: 'process_crash',
        message: 'Segmentation fault',
        isTransient: false,
        requiresAccountSwitch: false,
        shouldPersistToDB: true
      };

      expect(retryPolicy.shouldRetry(error, 1)).toBe(false);
      expect(retryPolicy.shouldRetry(error, 2)).toBe(false);
    });

    it('should retry timeouts', () => {
      const error: AgentError = {
        type: 'timeout',
        message: 'Process timed out',
        isTransient: true,
        requiresAccountSwitch: false,
        shouldPersistToDB: true
      };

      expect(retryPolicy.shouldRetry(error, 1)).toBe(true);
      expect(retryPolicy.shouldRetry(error, 2)).toBe(true);
      expect(retryPolicy.shouldRetry(error, 3)).toBe(false); // At max attempts
    });

    it('should not retry unknown errors', () => {
      const error: AgentError = {
        type: 'unknown',
        message: 'Something weird happened',
        isTransient: false,
        requiresAccountSwitch: false,
        shouldPersistToDB: true
      };

      expect(retryPolicy.shouldRetry(error, 1)).toBe(false);
      expect(retryPolicy.shouldRetry(error, 2)).toBe(false);
    });

    it('should not retry when at max attempts regardless of error type', () => {
      const error: AgentError = {
        type: 'auth_failure',
        message: 'Unauthorized',
        isTransient: true,
        requiresAccountSwitch: false,
        shouldPersistToDB: true
      };

      expect(retryPolicy.shouldRetry(error, 3)).toBe(false);
      expect(retryPolicy.shouldRetry(error, 4)).toBe(false);
    });
  });

  describe('getRetryDelay', () => {
    it('should return correct delay for each attempt', () => {
      expect(retryPolicy.getRetryDelay(1)).toBe(1000);
      expect(retryPolicy.getRetryDelay(2)).toBe(2000);
      expect(retryPolicy.getRetryDelay(3)).toBe(4000);
    });

    it('should cap delay at maximum for high attempts', () => {
      expect(retryPolicy.getRetryDelay(4)).toBe(4000);
      expect(retryPolicy.getRetryDelay(10)).toBe(4000);
    });
  });
});