import { describe, it, expect } from 'vitest';
import { computeDiff, getChangeColor, getChangeBackgroundColor, formatChangeSummary } from './diff';

describe('computeDiff', () => {
  it('should detect additions', () => {
    const oldContent = 'line1\nline2';
    const newContent = 'line1\nline2\nline3';

    const result = computeDiff(oldContent, newContent, 1);

    expect(result.additions).toBe(1);
    expect(result.deletions).toBe(0);
    expect(result.modifications).toBe(0);
    expect(result.changes).toHaveLength(1);
    expect(result.changes[0]!.changeType).toBe('addition');
    expect(result.changes[0]!.newContent).toBe('line3');
  });

  it('should detect deletions', () => {
    const oldContent = 'line1\nline2\nline3';
    const newContent = 'line1\nline2';

    const result = computeDiff(oldContent, newContent, 1);

    expect(result.additions).toBe(0);
    expect(result.deletions).toBe(1);
    expect(result.modifications).toBe(0);
    expect(result.changes[0]!.changeType).toBe('deletion');
    expect(result.changes[0]!.oldContent).toBe('line3');
  });

  it('should detect modifications', () => {
    const oldContent = 'line1\nline2\nline3';
    const newContent = 'line1\nchanged\nline3';

    const result = computeDiff(oldContent, newContent, 1);

    expect(result.additions).toBe(0);
    expect(result.deletions).toBe(0);
    expect(result.modifications).toBe(1);
    expect(result.changes[0]!.changeType).toBe('modification');
    expect(result.changes[0]!.oldContent).toBe('line2');
    expect(result.changes[0]!.newContent).toBe('changed');
  });

  it('should return no changes for identical content', () => {
    const content = 'line1\nline2\nline3';

    const result = computeDiff(content, content, 1);

    expect(result.additions).toBe(0);
    expect(result.deletions).toBe(0);
    expect(result.modifications).toBe(0);
    expect(result.changes).toHaveLength(0);
  });

  it('should track line numbers correctly', () => {
    const oldContent = 'a\nb\nc\nd';
    const newContent = 'a\nx\nc\nd';

    const result = computeDiff(oldContent, newContent, 1);

    expect(result.changes[0]!.lineNumber).toBe(2);
  });

  it('should handle empty old content', () => {
    const newContent = 'line1\nline2';

    const result = computeDiff('', newContent, 1);

    expect(result.additions).toBeGreaterThan(0);
    expect(result.deletions).toBe(0);
  });

  it('should handle empty new content', () => {
    const oldContent = 'line1\nline2';

    const result = computeDiff(oldContent, '', 1);

    expect(result.deletions).toBeGreaterThan(0);
    expect(result.additions).toBe(0);
  });

  it('should set revision ID on all changes', () => {
    const result = computeDiff('old', 'new', 42);

    expect(result.changes[0]!.revisionId).toBe(42);
  });
});

describe('getChangeColor', () => {
  it('should return green for additions', () => {
    expect(getChangeColor('addition')).toBe('#22c55e');
  });

  it('should return red for deletions', () => {
    expect(getChangeColor('deletion')).toBe('#ef4444');
  });

  it('should return amber for modifications', () => {
    expect(getChangeColor('modification')).toBe('#f59e0b');
  });
});

describe('getChangeBackgroundColor', () => {
  it('should return green background for additions', () => {
    expect(getChangeBackgroundColor('addition')).toBe('rgba(34, 197, 94, 0.15)');
  });

  it('should return red background for deletions', () => {
    expect(getChangeBackgroundColor('deletion')).toBe('rgba(239, 68, 68, 0.15)');
  });

  it('should return amber background for modifications', () => {
    expect(getChangeBackgroundColor('modification')).toBe('rgba(245, 158, 11, 0.15)');
  });
});

describe('formatChangeSummary', () => {
  it('should format additions only', () => {
    const summary = formatChangeSummary({ additions: 3, deletions: 0, modifications: 0, changes: [] });
    expect(summary).toBe('+3 added');
  });

  it('should format deletions only', () => {
    const summary = formatChangeSummary({ additions: 0, deletions: 2, modifications: 0, changes: [] });
    expect(summary).toBe('-2 removed');
  });

  it('should format modifications only', () => {
    const summary = formatChangeSummary({ additions: 0, deletions: 0, modifications: 1, changes: [] });
    expect(summary).toBe('~1 modified');
  });

  it('should format multiple change types', () => {
    const summary = formatChangeSummary({ additions: 2, deletions: 1, modifications: 3, changes: [] });
    expect(summary).toBe('+2 added, -1 removed, ~3 modified');
  });

  it('should return no changes message for empty diff', () => {
    const summary = formatChangeSummary({ additions: 0, deletions: 0, modifications: 0, changes: [] });
    expect(summary).toBe('No changes');
  });
});
