import { describe, it, expect } from 'vitest';
import {
  alignLeft,
  alignCenter,
  alignRight,
  alignTop,
  alignMiddle,
  alignBottom,
  distributeHorizontal,
  distributeVertical,
  centerOnArtboard,
} from '../alignment';
import type { BoundingRect } from '../alignment';

const items: BoundingRect[] = [
  { id: 'a', x: 10, y: 20, width: 30, height: 40 },
  { id: 'b', x: 50, y: 60, width: 20, height: 10 },
  { id: 'c', x: 100, y: 10, width: 40, height: 50 },
];

describe('alignment', () => {
  describe('alignLeft', () => {
    it('moves all items to the leftmost x', () => {
      const result = alignLeft(items);
      expect(result.every((r) => r.x === 10)).toBe(true);
    });
    it('preserves y positions', () => {
      const result = alignLeft(items);
      expect(result.map((r) => r.y)).toEqual([20, 60, 10]);
    });
  });

  describe('alignCenter', () => {
    it('centers all items on the average horizontal center', () => {
      const result = alignCenter(items);
      const centers = result.map((r, i) => r.x + items[i].width / 2);
      expect(centers[0]).toBeCloseTo(centers[1], 5);
      expect(centers[1]).toBeCloseTo(centers[2], 5);
    });
  });

  describe('alignRight', () => {
    it('aligns all items to the rightmost edge', () => {
      const result = alignRight(items);
      const maxRight = 100 + 40; // item c right edge
      for (let i = 0; i < result.length; i++) {
        expect(result[i].x + items[i].width).toBeCloseTo(maxRight, 5);
      }
    });
  });

  describe('alignTop', () => {
    it('moves all items to the topmost y', () => {
      const result = alignTop(items);
      expect(result.every((r) => r.y === 10)).toBe(true);
    });
  });

  describe('alignMiddle', () => {
    it('centers all items on the average vertical middle', () => {
      const result = alignMiddle(items);
      const middles = result.map((r, i) => r.y + items[i].height / 2);
      expect(middles[0]).toBeCloseTo(middles[1], 5);
      expect(middles[1]).toBeCloseTo(middles[2], 5);
    });
  });

  describe('alignBottom', () => {
    it('aligns all items to the bottommost edge', () => {
      const result = alignBottom(items);
      // Max bottom edge: max of (20+40=60, 60+10=70, 10+50=60) = 70
      const maxBot = Math.max(...items.map((i) => i.y + i.height));
      for (let i = 0; i < result.length; i++) {
        expect(result[i].y + items[i].height).toBeCloseTo(maxBot, 5);
      }
    });
  });

  describe('distributeHorizontal', () => {
    it('returns same positions for fewer than 3 items', () => {
      const two = items.slice(0, 2);
      const result = distributeHorizontal(two);
      expect(result[0].x).toBe(two[0].x);
      expect(result[1].x).toBe(two[1].x);
    });

    it('evenly spaces 3+ items horizontally', () => {
      const result = distributeHorizontal(items);
      // sorted by x: a(10), b(50), c(100)
      // gap should be equal between all items
      const sorted = [...result].sort((a, b) => a.x - b.x);
      const gap1 = sorted[1].x - (sorted[0].x + 30); // 30=width of a
      const gap2 = sorted[2].x - (sorted[1].x + 20); // 20=width of b
      expect(gap1).toBeCloseTo(gap2, 5);
    });
  });

  describe('distributeVertical', () => {
    it('returns same positions for fewer than 3 items', () => {
      const two = items.slice(0, 2);
      const result = distributeVertical(two);
      expect(result[0].y).toBe(two[0].y);
      expect(result[1].y).toBe(two[1].y);
    });

    it('evenly spaces 3+ items vertically', () => {
      const result = distributeVertical(items);
      const sorted = [...result].sort((a, b) => a.y - b.y);
      // sorted by y: c(10,h=50), a(20,h=40), b(60,h=10)
      const gap1 = sorted[1].y - (sorted[0].y + 50); // 50=height of c
      const gap2 = sorted[2].y - (sorted[1].y + 40); // 40=height of a
      expect(gap1).toBeCloseTo(gap2, 5);
    });
  });

  describe('centerOnArtboard', () => {
    it('returns empty array for empty input', () => {
      expect(centerOnArtboard([], 400, 400)).toEqual([]);
    });

    it('centers a single item on the artboard', () => {
      const single: BoundingRect[] = [
        { id: 'x', x: 0, y: 0, width: 100, height: 100 },
      ];
      const result = centerOnArtboard(single, 400, 400);
      expect(result[0].x).toBe(150);
      expect(result[0].y).toBe(150);
    });

    it('centers a group on the artboard', () => {
      const group: BoundingRect[] = [
        { id: 'a', x: 0, y: 0, width: 50, height: 50 },
        { id: 'b', x: 50, y: 0, width: 50, height: 50 },
      ];
      const result = centerOnArtboard(group, 400, 400);
      // Group width = 100, centered at (150, 175)
      const groupLeft = Math.min(result[0].x, result[1].x);
      const groupRight = Math.max(result[0].x + 50, result[1].x + 50);
      expect((groupLeft + groupRight) / 2).toBeCloseTo(200, 5);
    });
  });
});
