/**
 * Contrast Ratio Tests
 * Action 11.1.1.5: Automated contrast testing
 * 
 * Validates that all design system color combinations meet WCAG AA standards.
 */

import { describe, it, expect } from 'vitest';
import {
  getRelativeLuminance,
  getContrastRatio,
  meetsWCAGAA,
  meetsWCAGAAA,
  parseRGB,
} from '../utils/contrast';

describe('Contrast Ratio Utilities', () => {
  describe('getRelativeLuminance', () => {
    it('should calculate luminance for white', () => {
      const luminance = getRelativeLuminance(255, 255, 255);
      expect(luminance).toBeCloseTo(1.0, 2);
    });

    it('should calculate luminance for black', () => {
      const luminance = getRelativeLuminance(0, 0, 0);
      expect(luminance).toBeCloseTo(0.0, 3);
    });

    it('should calculate luminance for gray', () => {
      const luminance = getRelativeLuminance(128, 128, 128);
      expect(luminance).toBeGreaterThan(0);
      expect(luminance).toBeLessThan(1);
    });
  });

  describe('getContrastRatio', () => {
    it('should calculate maximum contrast (white on black)', () => {
      const ratio = getContrastRatio([255, 255, 255], [0, 0, 0]);
      expect(ratio).toBeCloseTo(21.0, 1);
    });

    it('should calculate minimum contrast (same colors)', () => {
      const ratio = getContrastRatio([255, 255, 255], [255, 255, 255]);
      expect(ratio).toBeCloseTo(1.0, 2);
    });

    it('should be symmetric (order-independent)', () => {
      const ratio1 = getContrastRatio([255, 255, 255], [128, 128, 128]);
      const ratio2 = getContrastRatio([128, 128, 128], [255, 255, 255]);
      expect(ratio1).toBeCloseTo(ratio2, 2);
    });
  });

  describe('meetsWCAGAA', () => {
    it('should pass for white on black (normal text)', () => {
      const ratio = getContrastRatio([255, 255, 255], [0, 0, 0]);
      expect(meetsWCAGAA(ratio, false)).toBe(true);
    });

    it('should pass for white on dark background (normal text)', () => {
      const ratio = getContrastRatio([255, 255, 255], [11, 12, 16]); // kodo-void
      expect(meetsWCAGAA(ratio, false)).toBe(true);
      expect(ratio).toBeGreaterThan(4.5);
    });

    it('should fail for low contrast (normal text)', () => {
      expect(meetsWCAGAA(3.0, false)).toBe(false);
    });

    it('should pass for lower ratio with large text', () => {
      expect(meetsWCAGAA(3.5, true)).toBe(true);
    });
  });

  describe('meetsWCAGAAA', () => {
    it('should pass for white on black', () => {
      const ratio = getContrastRatio([255, 255, 255], [0, 0, 0]);
      expect(meetsWCAGAAA(ratio, false)).toBe(true);
    });

    it('should fail for 6:1 ratio (normal text)', () => {
      expect(meetsWCAGAAA(6.0, false)).toBe(false);
    });

    it('should pass for 7:1 ratio (normal text)', () => {
      expect(meetsWCAGAAA(7.0, false)).toBe(true);
    });
  });

  describe('parseRGB', () => {
    it('should parse space-separated RGB', () => {
      const rgb = parseRGB('255 255 255');
      expect(rgb).toEqual([255, 255, 255]);
    });

    it('should parse rgb() format', () => {
      const rgb = parseRGB('rgb(255, 255, 255)');
      expect(rgb).toEqual([255, 255, 255]);
    });

    it('should return null for invalid format', () => {
      expect(parseRGB('invalid')).toBeNull();
      expect(parseRGB('#ffffff')).toBeNull();
    });
  });
});

describe('Design System Color Contrast', () => {
  // Kodo Design System colors from index.css
  const colors = {
    void: [11, 12, 16] as [number, number, number],
    ink: [23, 25, 35] as [number, number, number],
    graphite: [31, 40, 51] as [number, number, number],
    slate: [44, 54, 67] as [number, number, number],
    steel: [59, 69, 84] as [number, number, number],
    textMain: [255, 255, 255] as [number, number, number], // White
    contentDim: [156, 163, 175] as [number, number, number], // Gray-400
  };

  describe('Primary Text (White) on Backgrounds', () => {
    const backgrounds = [
      { name: 'void', rgb: colors.void },
      { name: 'ink', rgb: colors.ink },
      { name: 'graphite', rgb: colors.graphite },
      { name: 'slate', rgb: colors.slate },
      { name: 'steel', rgb: colors.steel },
    ];

    backgrounds.forEach((bg) => {
      it(`should meet WCAG AA for white text on ${bg.name}`, () => {
        const ratio = getContrastRatio(colors.textMain, bg.rgb);
        expect(ratio).toBeGreaterThan(4.5);
        expect(meetsWCAGAA(ratio, false)).toBe(true);
      });

      it(`should meet WCAG AAA for white text on ${bg.name}`, () => {
        const ratio = getContrastRatio(colors.textMain, bg.rgb);
        expect(ratio).toBeGreaterThan(7.0);
        expect(meetsWCAGAAA(ratio, false)).toBe(true);
      });
    });
  });

  describe('Secondary Text (Dim) on Backgrounds', () => {
    const backgrounds = [
      { name: 'void', rgb: colors.void },
      { name: 'ink', rgb: colors.ink },
      { name: 'graphite', rgb: colors.graphite },
      { name: 'slate', rgb: colors.slate },
      { name: 'steel', rgb: colors.steel },
    ];

    backgrounds.forEach((bg) => {
      it(`should meet WCAG AA for dim text on ${bg.name}`, () => {
        const ratio = getContrastRatio(colors.contentDim, bg.rgb);
        expect(ratio).toBeGreaterThan(4.5);
        expect(meetsWCAGAA(ratio, false)).toBe(true);
      });
    });
  });

  describe('Text with Opacity', () => {
    // Simulate opacity by blending with background
    // opacity-80: ~80% white = ~204 RGB
    // opacity-90: ~90% white = ~230 RGB
    const opacity80 = [204, 204, 204] as [number, number, number];
    const opacity90 = [230, 230, 230] as [number, number, number];

    const backgrounds = [
      { name: 'void', rgb: colors.void },
      { name: 'ink', rgb: colors.ink },
      { name: 'graphite', rgb: colors.graphite },
    ];

    backgrounds.forEach((bg) => {
      it(`should meet WCAG AA for opacity-80 text on ${bg.name}`, () => {
        const ratio = getContrastRatio(opacity80, bg.rgb);
        expect(ratio).toBeGreaterThan(4.5);
        expect(meetsWCAGAA(ratio, false)).toBe(true);
      });

      it(`should meet WCAG AA for opacity-90 text on ${bg.name}`, () => {
        const ratio = getContrastRatio(opacity90, bg.rgb);
        expect(ratio).toBeGreaterThan(4.5);
        expect(meetsWCAGAA(ratio, false)).toBe(true);
      });
    });
  });
});
