import { render } from '@testing-library/react';
import { describe, it, expect } from 'vitest';
import { IsotypeFrames } from './IsotypeFrames';
import { ISOTYPE_FRAME_VARIANTS, ISOTYPE_FRAME_VARIANT_IDS } from './frame-variants';
import { ISOTYPE_COLORS } from './patterns';
import React from 'react';

describe('IsotypeFrames', () => {
  it('renders two overlapping rects', () => {
    const { container } = render(<IsotypeFrames />);
    expect(container.querySelectorAll('rect')).toHaveLength(2);
  });

  it('defaults to the blue-magenta variant', () => {
    const { container } = render(<IsotypeFrames />);
    const rects = container.querySelectorAll('rect');
    const [backKey, frontKey] = ISOTYPE_FRAME_VARIANTS['blue-magenta'];
    expect(rects[0].getAttribute('stroke')).toBe(ISOTYPE_COLORS[backKey]);
    expect(rects[1].getAttribute('stroke')).toBe(ISOTYPE_COLORS[frontKey]);
  });

  it('renders every registered variant with the right stroke colors', () => {
    for (const variant of ISOTYPE_FRAME_VARIANT_IDS) {
      const { container } = render(<IsotypeFrames variant={variant} />);
      const rects = container.querySelectorAll('rect');
      const [backKey, frontKey] = ISOTYPE_FRAME_VARIANTS[variant];
      expect(rects[0].getAttribute('stroke')).toBe(ISOTYPE_COLORS[backKey]);
      expect(rects[1].getAttribute('stroke')).toBe(ISOTYPE_COLORS[frontKey]);
    }
  });

  it('renders each rect hollow (fill="none")', () => {
    const { container } = render(<IsotypeFrames />);
    container.querySelectorAll('rect').forEach(rect => {
      expect(rect.getAttribute('fill')).toBe('none');
    });
  });

  it('passes className through to the root', () => {
    const { container } = render(<IsotypeFrames className="w-64" />);
    expect((container.firstChild as HTMLElement).className).toContain('w-64');
  });

  it('offsets the front frame diagonally from the back frame by a sixth of the shared size', () => {
    const { container } = render(<IsotypeFrames />);
    const [back, front] = Array.from(container.querySelectorAll('rect'));

    const backX = Number(back.getAttribute('x'));
    const backY = Number(back.getAttribute('y'));
    const backSize = Number(back.getAttribute('width'));
    const frontX = Number(front.getAttribute('x'));
    const frontY = Number(front.getAttribute('y'));
    const frontSize = Number(front.getAttribute('width'));

    expect(backSize).toBe(frontSize);
    expect(frontX - backX).toBeCloseTo(backSize / 6);
    expect(frontY - backY).toBeCloseTo(backSize / 6);
  });

  it('renders both frames fully opaque and blends their intersection via mix-blend-mode on the front frame', () => {
    const { container } = render(<IsotypeFrames />);
    const [back, front] = Array.from(container.querySelectorAll('rect'));

    expect(back.getAttribute('opacity')).toBeNull();
    expect(front.getAttribute('opacity')).toBeNull();
    expect(front.style.mixBlendMode).toBeTruthy();
    expect(front.style.mixBlendMode).not.toBe('normal');
  });

  it('isolates the blend mode to the two frames via the root isolate class', () => {
    const { container } = render(<IsotypeFrames />);
    expect((container.firstChild as HTMLElement).className).toContain('isolate');
  });

  it('expands the viewBox so no edge of the stroked frames is clipped', () => {
    const { container } = render(<IsotypeFrames />);
    const svg = container.querySelector('svg')!;
    const [minX, minY, width, height] = svg.getAttribute('viewBox')!.split(' ').map(Number);

    container.querySelectorAll('rect').forEach(rect => {
      const x = Number(rect.getAttribute('x'));
      const y = Number(rect.getAttribute('y'));
      const size = Number(rect.getAttribute('width'));
      const half = Number(rect.getAttribute('stroke-width')) / 2;

      expect(x - half).toBeGreaterThanOrEqual(minX);
      expect(y - half).toBeGreaterThanOrEqual(minY);
      expect(x + size + half).toBeLessThanOrEqual(minX + width);
      expect(y + size + half).toBeLessThanOrEqual(minY + height);
    });
  });
});
