import { describe, it, expect } from 'vitest';
import { computeDiff, countChanges } from '../../../src/utils/diff.js';

describe('computeDiff - 计算文件差异', () => {
  describe('新文件', () => {
    it('新文件所有行标记为新增', () => {
      const diff = computeDiff(null, 'line1\nline2\nline3');

      expect(diff.isNew).toBe(true);
      expect(diff.oldContent).toBeNull();
      expect(diff.hunks).toHaveLength(1);

      const hunk = diff.hunks[0];
      expect(hunk.oldStart).toBe(0);
      expect(hunk.oldCount).toBe(0);
      expect(hunk.newStart).toBe(1);
      expect(hunk.newCount).toBe(3);

      expect(hunk.lines).toHaveLength(3);
      expect(hunk.lines.every((l) => l.type === 'add')).toBe(true);
    });

    it('空新文件', () => {
      const diff = computeDiff(null, '');

      expect(diff.isNew).toBe(true);
      expect(diff.hunks).toHaveLength(1);
      expect(diff.hunks[0].lines).toHaveLength(1); // 空行也是一行
    });
  });

  describe('修改文件', () => {
    it('相同内容无变化', () => {
      const content = 'line1\nline2\nline3';
      const diff = computeDiff(content, content);

      expect(diff.isNew).toBe(false);
      expect(diff.hunks).toHaveLength(0);
    });

    it('单行修改', () => {
      const oldContent = 'line1\nline2\nline3';
      const newContent = 'line1\nmodified\nline3';
      const diff = computeDiff(oldContent, newContent);

      expect(diff.isNew).toBe(false);
      expect(diff.hunks.length).toBeGreaterThan(0);

      // 应该有删除和新增
      const allLines = diff.hunks.flatMap((h) => h.lines);
      expect(allLines.some((l) => l.type === 'remove' && l.content === 'line2')).toBe(true);
      expect(allLines.some((l) => l.type === 'add' && l.content === 'modified')).toBe(true);
    });

    it('添加行', () => {
      const oldContent = 'line1\nline3';
      const newContent = 'line1\nline2\nline3';
      const diff = computeDiff(oldContent, newContent);

      expect(diff.isNew).toBe(false);
      const allLines = diff.hunks.flatMap((h) => h.lines);
      expect(allLines.some((l) => l.type === 'add' && l.content === 'line2')).toBe(true);
    });

    it('删除行', () => {
      const oldContent = 'line1\nline2\nline3';
      const newContent = 'line1\nline3';
      const diff = computeDiff(oldContent, newContent);

      expect(diff.isNew).toBe(false);
      const allLines = diff.hunks.flatMap((h) => h.lines);
      expect(allLines.some((l) => l.type === 'remove' && l.content === 'line2')).toBe(true);
    });

    it('全部替换', () => {
      const oldContent = 'old1\nold2\nold3';
      const newContent = 'new1\nnew2';
      const diff = computeDiff(oldContent, newContent);

      expect(diff.isNew).toBe(false);
      expect(diff.hunks.length).toBeGreaterThan(0);

      const changes = countChanges(diff);
      expect(changes.deletions).toBeGreaterThan(0);
      expect(changes.additions).toBeGreaterThan(0);
    });
  });

  describe('特殊情况', () => {
    it('空文件变为非空', () => {
      const diff = computeDiff('', 'new content');

      expect(diff.isNew).toBe(false);
      expect(diff.hunks.length).toBeGreaterThan(0);
    });

    it('非空文件变为空', () => {
      const diff = computeDiff('old content', '');

      expect(diff.isNew).toBe(false);
      expect(diff.hunks.length).toBeGreaterThan(0);
    });

    it('包含空行的内容', () => {
      const oldContent = 'line1\n\nline3';
      const newContent = 'line1\nline2\n\nline3';
      const diff = computeDiff(oldContent, newContent);

      expect(diff.isNew).toBe(false);
      // 应该正确处理空行
    });

    it('单行文件', () => {
      const diff = computeDiff('old', 'new');

      expect(diff.isNew).toBe(false);
      expect(diff.hunks.length).toBeGreaterThan(0);
    });
  });

  describe('行号正确性', () => {
    it('新增行有正确的行号', () => {
      const diff = computeDiff(null, 'line1\nline2\nline3');

      const lines = diff.hunks[0].lines;
      expect(lines[0].lineNumber).toBe(1);
      expect(lines[1].lineNumber).toBe(2);
      expect(lines[2].lineNumber).toBe(3);
    });
  });
});

describe('countChanges - 统计变更数量', () => {
  it('新文件计算新增行', () => {
    const diff = computeDiff(null, 'line1\nline2\nline3');
    const changes = countChanges(diff);

    expect(changes.additions).toBe(3);
    expect(changes.deletions).toBe(0);
  });

  it('修改文件计算增删', () => {
    const diff = computeDiff('old1\nold2', 'new1\nold2\nnew2');
    const changes = countChanges(diff);

    expect(changes.additions).toBeGreaterThan(0);
    expect(changes.deletions).toBeGreaterThan(0);
  });

  it('空 diff 返回零', () => {
    const diff = computeDiff('same', 'same');
    const changes = countChanges(diff);

    expect(changes.additions).toBe(0);
    expect(changes.deletions).toBe(0);
  });
});


describe('DiffResult 结构', () => {
  it('包含所有必要字段', () => {
    const diff = computeDiff('old', 'new');

    expect(diff).toHaveProperty('oldContent');
    expect(diff).toHaveProperty('newContent');
    expect(diff).toHaveProperty('isNew');
    expect(diff).toHaveProperty('hunks');
  });

  it('hunk 包含所有必要字段', () => {
    const diff = computeDiff('old', 'new');

    if (diff.hunks.length > 0) {
      const hunk = diff.hunks[0];
      expect(hunk).toHaveProperty('oldStart');
      expect(hunk).toHaveProperty('oldCount');
      expect(hunk).toHaveProperty('newStart');
      expect(hunk).toHaveProperty('newCount');
      expect(hunk).toHaveProperty('lines');
    }
  });

  it('line 包含所有必要字段', () => {
    const diff = computeDiff(null, 'content');

    const line = diff.hunks[0].lines[0];
    expect(line).toHaveProperty('type');
    expect(line).toHaveProperty('lineNumber');
    expect(line).toHaveProperty('content');
  });
});

describe('LCS 算法测试', () => {
  it('相同前缀保留', () => {
    const oldContent = 'prefix\ncommon\nold';
    const newContent = 'prefix\ncommon\nnew';
    const diff = computeDiff(oldContent, newContent);

    // common 行应该保持为上下文
    const contextLines = diff.hunks.flatMap((h) =>
      h.lines.filter((l) => l.type === 'context')
    );
    // prefix 和 common 可能作为上下文保留
    expect(diff.hunks.length).toBeGreaterThan(0);
  });

  it('相同后缀保留', () => {
    const oldContent = 'old\ncommon\nsuffix';
    const newContent = 'new\ncommon\nsuffix';
    const diff = computeDiff(oldContent, newContent);

    expect(diff.hunks.length).toBeGreaterThan(0);
  });

  it('完全不同的内容', () => {
    const oldContent = 'a\nb\nc';
    const newContent = 'x\ny\nz';
    const diff = computeDiff(oldContent, newContent);

    const changes = countChanges(diff);
    expect(changes.additions).toBe(3);
    expect(changes.deletions).toBe(3);
  });
});


describe('实际代码场景', () => {
  it('函数修改', () => {
    const oldContent = `function hello() {
  console.log("Hello");
}`;

    const newContent = `function hello() {
  console.log("Hello World");
  return true;
}`;

    const diff = computeDiff(oldContent, newContent);

    expect(diff.isNew).toBe(false);
    expect(diff.hunks.length).toBeGreaterThan(0);

    const changes = countChanges(diff);
    expect(changes.additions).toBeGreaterThan(0);
  });

  it('导入语句添加', () => {
    const oldContent = `import { a } from 'module';

export function test() {}`;

    const newContent = `import { a } from 'module';
import { b } from 'another';

export function test() {}`;

    const diff = computeDiff(oldContent, newContent);

    const changes = countChanges(diff);
    expect(changes.additions).toBeGreaterThan(0);
  });

  it('配置文件修改', () => {
    const oldContent = `{
  "name": "test",
  "version": "1.0.0"
}`;

    const newContent = `{
  "name": "test",
  "version": "1.1.0",
  "description": "Added description"
}`;

    const diff = computeDiff(oldContent, newContent);

    expect(diff.hunks.length).toBeGreaterThan(0);
  });
});
