/**
 * Unit Tests for Token Calculation Utilities
 *
 * Tests the token estimation, cost calculation, and credit checking functions
 */

import {
  estimateTokens,
  calculateCost,
  getCreditAllocationForTier,
  estimateProcessingTime,
  formatTokenCount,
  formatCost,
} from '../../../utils/tokenCalculation';

describe('Token Calculation Utils', () => {

  describe('estimateTokens', () => {
    it('should estimate tokens for short content', () => {
      const content = 'Hello world';
      const tokens = estimateTokens(content);

      // "Hello world" = 11 chars / 4 = 2.75 ~= 3 base tokens
      // + 50 prompt overhead
      // + 3 output tokens
      // Total: 3 + 50 + 3 = 56 tokens
      expect(tokens).toBe(56);
    });

    it('should estimate tokens for medium content', () => {
      const content = 'A'.repeat(400); // 400 characters
      const tokens = estimateTokens(content);

      // 400 / 4 = 100 base tokens
      // + 50 prompt overhead
      // + 100 output tokens
      // Total: 250 tokens
      expect(tokens).toBe(250);
    });

    it('should estimate tokens for long content', () => {
      const content = 'A'.repeat(4000); // 4000 characters
      const tokens = estimateTokens(content);

      // 4000 / 4 = 1000 base tokens
      // + 50 prompt overhead
      // + 1000 output tokens
      // Total: 2050 tokens
      expect(tokens).toBe(2050);
    });

    it('should handle empty content', () => {
      const content = '';
      const tokens = estimateTokens(content);

      // 0 base tokens + 50 prompt + 0 output = 50
      expect(tokens).toBe(50);
    });

    it('should accept source and target language parameters', () => {
      const content = 'Hello world';
      const tokens = estimateTokens(content, 'en', 'fr');

      // Should still calculate same tokens (languages don't affect estimation in current impl)
      expect(tokens).toBe(56);
    });
  });

  describe('calculateCost', () => {
    it('calculates Gemini 3.1 Flash-Lite input and output token costs independently', () => {
      expect(calculateCost(1_000_000, 1_000_000, 'gemini-3.1-flash-lite')).toBe(1.75);
    });

    it('uses the Gemini 2.5 Flash provider rates for fallback requests', () => {
      expect(calculateCost(1_000_000, 1_000_000, 'gemini-2.5-flash')).toBe(2.8);
    });

    it('does not silently apply customer pricing to an unknown provider model', () => {
      expect(() => calculateCost(1000, 1000, 'unknown-model')).toThrow(
        'Provider pricing is not configured for model unknown-model'
      );
    });

    it('handles zero tokens', () => {
      expect(calculateCost(0, 0, 'gemini-3.1-flash-lite')).toBe(0);
    });
  });

  describe('getCreditAllocationForTier', () => {
    it('should return correct allocation for starter tier', () => {
      const allocation = getCreditAllocationForTier('starter');
      expect(allocation).toBe(1000000);
    });

    it('should return correct allocation for professional tier', () => {
      const allocation = getCreditAllocationForTier('professional');
      expect(allocation).toBe(4000000);
    });

    it('should return correct allocation for enterprise tier', () => {
      const allocation = getCreditAllocationForTier('enterprise');
      expect(allocation).toBe(15000000);
    });
  });

  describe('estimateProcessingTime', () => {
    it('should estimate processing time from token count', () => {
      const content = 'A'.repeat(1000);
      const time = estimateProcessingTime(content);

      expect(time).toBe(17715);
    });

    it('should be deterministic for the same content', () => {
      const content = 'A'.repeat(1000);
      const first = estimateProcessingTime(content);
      const second = estimateProcessingTime(content);

      expect(second).toBe(first);
    });

    it('should include cold start overhead', () => {
      const content = ''; // Minimal content
      const time = estimateProcessingTime(content);

      // Even with no content, should have cold start overhead (2000ms)
      expect(time).toBeGreaterThanOrEqual(2000);
    });

    it('should increase with content length', () => {
      const shortContent = 'A'.repeat(100);
      const longContent = 'A'.repeat(1000);

      const shortTime = estimateProcessingTime(shortContent);
      const longTime = estimateProcessingTime(longContent);

      expect(longTime).toBeGreaterThan(shortTime);
    });
  });

  describe('formatTokenCount', () => {
    it('should format small numbers without suffix', () => {
      expect(formatTokenCount(0)).toBe('0');
      expect(formatTokenCount(100)).toBe('100');
      expect(formatTokenCount(999)).toBe('999');
    });

    it('should format thousands with K suffix', () => {
      expect(formatTokenCount(1000)).toBe('1.0K');
      expect(formatTokenCount(1500)).toBe('1.5K');
      expect(formatTokenCount(999999)).toBe('1000.0K');
    });

    it('should format millions with M suffix', () => {
      expect(formatTokenCount(1000000)).toBe('1.0M');
      expect(formatTokenCount(1500000)).toBe('1.5M');
      expect(formatTokenCount(2000000)).toBe('2.0M');
    });

    it('should round to 1 decimal place', () => {
      expect(formatTokenCount(1234)).toBe('1.2K');
      expect(formatTokenCount(1567000)).toBe('1.6M');
    });
  });

  describe('formatCost', () => {
    it('should format very small costs with 4 decimal places', () => {
      expect(formatCost(0.0001)).toBe('$0.0001');
      expect(formatCost(0.0012)).toBe('$0.0012');
      expect(formatCost(0.0099)).toBe('$0.0099');
    });

    it('should format small costs with 3 decimal places', () => {
      expect(formatCost(0.01)).toBe('$0.010');
      expect(formatCost(0.123)).toBe('$0.123');
      expect(formatCost(0.999)).toBe('$0.999');
    });

    it('should format regular costs with 2 decimal places', () => {
      expect(formatCost(1.00)).toBe('$1.00');
      expect(formatCost(1.50)).toBe('$1.50');
      expect(formatCost(99.99)).toBe('$99.99');
    });

    it('should handle zero cost', () => {
      expect(formatCost(0)).toBe('$0.0000');
    });

    it('should handle large costs', () => {
      expect(formatCost(1000)).toBe('$1000.00');
      expect(formatCost(9999.99)).toBe('$9999.99');
    });
  });
});
