import { describe, it, expect, vi, beforeEach } from 'vitest';
import {
  isImagePath,
  extractImageReferences,
  formatFileSize,
  loadImage,
  loadImages,
  IMAGE_EXTENSIONS,
} from '../../../src/utils/image.js';

// Mock fs/promises
vi.mock('fs/promises', () => ({
  readFile: vi.fn(),
  stat: vi.fn(),
}));

import * as fs from 'fs/promises';

describe('Image Utils - 图片处理工具', () => {
  describe('IMAGE_EXTENSIONS', () => {
    it('包含常见图片扩展名', () => {
      expect(IMAGE_EXTENSIONS).toContain('.png');
      expect(IMAGE_EXTENSIONS).toContain('.jpg');
      expect(IMAGE_EXTENSIONS).toContain('.jpeg');
      expect(IMAGE_EXTENSIONS).toContain('.gif');
      expect(IMAGE_EXTENSIONS).toContain('.webp');
    });
  });

  describe('isImagePath - 判断是否为图片路径', () => {
    it('识别 PNG 文件', () => {
      expect(isImagePath('screenshot.png')).toBe(true);
      expect(isImagePath('path/to/image.PNG')).toBe(true);
    });

    it('识别 JPG/JPEG 文件', () => {
      expect(isImagePath('photo.jpg')).toBe(true);
      expect(isImagePath('photo.jpeg')).toBe(true);
      expect(isImagePath('photo.JPG')).toBe(true);
    });

    it('识别 GIF 文件', () => {
      expect(isImagePath('animation.gif')).toBe(true);
    });

    it('识别 WebP 文件', () => {
      expect(isImagePath('modern.webp')).toBe(true);
    });

    it('不识别非图片文件', () => {
      expect(isImagePath('document.txt')).toBe(false);
      expect(isImagePath('script.ts')).toBe(false);
      expect(isImagePath('data.json')).toBe(false);
      expect(isImagePath('readme.md')).toBe(false);
    });

    it('处理没有扩展名的文件', () => {
      expect(isImagePath('noextension')).toBe(false);
      expect(isImagePath('Makefile')).toBe(false);
    });
  });

  describe('extractImageReferences - 提取图片引用', () => {
    it('提取单个 @ 引用', () => {
      const result = extractImageReferences('请分析这张图片 @screenshot.png');
      expect(result.imagePaths).toEqual(['screenshot.png']);
      expect(result.textContent).toBe('请分析这张图片');
    });

    it('提取多个 @ 引用', () => {
      const result = extractImageReferences('对比 @before.png 和 @after.jpg');
      expect(result.imagePaths).toEqual(['before.png', 'after.jpg']);
      expect(result.textContent).toBe('对比 和');
    });

    it('提取带路径的图片引用', () => {
      const result = extractImageReferences('分析 @./images/test.png');
      expect(result.imagePaths).toEqual(['./images/test.png']);
    });

    it('提取绝对路径图片引用', () => {
      const result = extractImageReferences('查看 @/tmp/screenshot.png');
      expect(result.imagePaths).toEqual(['/tmp/screenshot.png']);
    });

    it('提取带空格的绝对路径（自动匹配到扩展名）', () => {
      const result = extractImageReferences('这张图片内容是什么？@/Users/xd/Adobe Express - file.png');
      expect(result.imagePaths).toEqual(['/Users/xd/Adobe Express - file.png']);
      expect(result.textContent).toBe('这张图片内容是什么？');
    });

    it('提取带引号的路径（支持空格）', () => {
      const result = extractImageReferences('分析 @"./my images/test photo.png"');
      expect(result.imagePaths).toEqual(['./my images/test photo.png']);
      expect(result.textContent).toBe('分析');
    });

    it('提取带单引号的路径', () => {
      const result = extractImageReferences("查看 @'./path with spaces/image.jpg'");
      expect(result.imagePaths).toEqual(['./path with spaces/image.jpg']);
      expect(result.textContent).toBe('查看');
    });

    it('忽略非图片的 @ 引用', () => {
      const result = extractImageReferences('请查看 @readme.md 文件');
      expect(result.imagePaths).toEqual([]);
      expect(result.textContent).toBe('请查看 @readme.md 文件');
    });

    it('忽略邮箱地址', () => {
      const result = extractImageReferences('联系 user@example.com 了解详情');
      expect(result.imagePaths).toEqual([]);
      expect(result.textContent).toBe('联系 user@example.com 了解详情');
    });

    it('混合图片和非图片引用', () => {
      const result = extractImageReferences(
        '查看 @screenshot.png 和 @config.json'
      );
      expect(result.imagePaths).toEqual(['screenshot.png']);
      expect(result.textContent).toBe('查看 和 @config.json');
    });

    it('没有引用时返回原文本', () => {
      const result = extractImageReferences('这是一段普通文本');
      expect(result.imagePaths).toEqual([]);
      expect(result.textContent).toBe('这是一段普通文本');
    });

    it('只有图片引用时文本内容为空', () => {
      const result = extractImageReferences('@image.png');
      expect(result.imagePaths).toEqual(['image.png']);
      expect(result.textContent).toBe('');
    });

    it('处理多个空格', () => {
      const result = extractImageReferences('   @test.png   描述   ');
      expect(result.imagePaths).toEqual(['test.png']);
      expect(result.textContent.trim()).toBe('描述');
    });
  });

  describe('formatFileSize - 格式化文件大小', () => {
    it('格式化字节', () => {
      expect(formatFileSize(0)).toBe('0B');
      expect(formatFileSize(100)).toBe('100B');
      expect(formatFileSize(1023)).toBe('1023B');
    });

    it('格式化 KB', () => {
      expect(formatFileSize(1024)).toBe('1.0KB');
      expect(formatFileSize(1536)).toBe('1.5KB');
      expect(formatFileSize(10240)).toBe('10.0KB');
    });

    it('格式化 MB', () => {
      expect(formatFileSize(1024 * 1024)).toBe('1.0MB');
      expect(formatFileSize(1024 * 1024 * 2.5)).toBe('2.5MB');
    });

    it('大文件以 MB 为单位', () => {
      expect(formatFileSize(1024 * 1024 * 1024)).toBe('1024.0MB');
    });
  });

  describe('loadImage - 加载图片文件', () => {
    beforeEach(() => {
      vi.clearAllMocks();
    });

    it('成功加载 PNG 图片', async () => {
      const mockBuffer = Buffer.from('fake image data');
      vi.mocked(fs.readFile).mockResolvedValue(mockBuffer);
      vi.mocked(fs.stat).mockResolvedValue({ size: mockBuffer.length } as any);

      const result = await loadImage('/test/image.png');

      expect(result.success).toBe(true);
      expect(result.image).toBeDefined();
      expect(result.image?.filename).toBe('image.png');
      expect(result.image?.extension).toBe('.png');
      expect(result.image?.mimeType).toBe('image/png');
      expect(result.image?.base64).toBe(mockBuffer.toString('base64'));
    });

    it('成功加载 JPG 图片', async () => {
      const mockBuffer = Buffer.from('fake jpg data');
      vi.mocked(fs.readFile).mockResolvedValue(mockBuffer);
      vi.mocked(fs.stat).mockResolvedValue({ size: mockBuffer.length } as any);

      const result = await loadImage('/test/photo.jpg');

      expect(result.success).toBe(true);
      expect(result.image?.mimeType).toBe('image/jpeg');
    });

    it('成功加载 JPEG 图片', async () => {
      const mockBuffer = Buffer.from('fake jpeg data');
      vi.mocked(fs.readFile).mockResolvedValue(mockBuffer);
      vi.mocked(fs.stat).mockResolvedValue({ size: mockBuffer.length } as any);

      const result = await loadImage('/test/photo.jpeg');

      expect(result.success).toBe(true);
      expect(result.image?.mimeType).toBe('image/jpeg');
    });

    it('成功加载 GIF 图片', async () => {
      const mockBuffer = Buffer.from('fake gif data');
      vi.mocked(fs.readFile).mockResolvedValue(mockBuffer);
      vi.mocked(fs.stat).mockResolvedValue({ size: mockBuffer.length } as any);

      const result = await loadImage('/test/animation.gif');

      expect(result.success).toBe(true);
      expect(result.image?.mimeType).toBe('image/gif');
    });

    it('成功加载 WebP 图片', async () => {
      const mockBuffer = Buffer.from('fake webp data');
      vi.mocked(fs.readFile).mockResolvedValue(mockBuffer);
      vi.mocked(fs.stat).mockResolvedValue({ size: mockBuffer.length } as any);

      const result = await loadImage('/test/modern.webp');

      expect(result.success).toBe(true);
      expect(result.image?.mimeType).toBe('image/webp');
    });

    it('返回正确的 dataUrl', async () => {
      const mockBuffer = Buffer.from('test data');
      vi.mocked(fs.readFile).mockResolvedValue(mockBuffer);
      vi.mocked(fs.stat).mockResolvedValue({ size: mockBuffer.length } as any);

      const result = await loadImage('/test/image.png');

      expect(result.image?.dataUrl).toBe(
        `data:image/png;base64,${mockBuffer.toString('base64')}`
      );
    });

    it('不支持的格式返回错误', async () => {
      const result = await loadImage('/test/document.txt');

      expect(result.success).toBe(false);
      expect(result.error).toContain('不支持的图片格式');
      expect(result.error).toContain('.txt');
    });

    it('文件不存在返回错误', async () => {
      const error = new Error('File not found');
      (error as any).code = 'ENOENT';
      vi.mocked(fs.readFile).mockRejectedValue(error);

      const result = await loadImage('/nonexistent/image.png');

      expect(result.success).toBe(false);
      expect(result.error).toContain('图片文件不存在');
    });

    it('读取文件错误返回错误信息', async () => {
      vi.mocked(fs.readFile).mockRejectedValue(new Error('Permission denied'));

      const result = await loadImage('/test/image.png');

      expect(result.success).toBe(false);
      expect(result.error).toContain('加载图片失败');
      expect(result.error).toContain('Permission denied');
    });

    it('处理相对路径', async () => {
      const mockBuffer = Buffer.from('test');
      vi.mocked(fs.readFile).mockResolvedValue(mockBuffer);
      vi.mocked(fs.stat).mockResolvedValue({ size: mockBuffer.length } as any);

      const result = await loadImage('./relative/image.png', '/workdir');

      expect(result.success).toBe(true);
      expect(fs.readFile).toHaveBeenCalledWith(
        expect.stringContaining('relative/image.png')
      );
    });

    it('处理大写扩展名', async () => {
      const mockBuffer = Buffer.from('test');
      vi.mocked(fs.readFile).mockResolvedValue(mockBuffer);
      vi.mocked(fs.stat).mockResolvedValue({ size: mockBuffer.length } as any);

      const result = await loadImage('/test/image.PNG');

      expect(result.success).toBe(true);
      expect(result.image?.mimeType).toBe('image/png');
    });
  });

  describe('loadImages - 批量加载图片', () => {
    beforeEach(() => {
      vi.clearAllMocks();
    });

    it('成功加载多张图片', async () => {
      const mockBuffer = Buffer.from('test');
      vi.mocked(fs.readFile).mockResolvedValue(mockBuffer);
      vi.mocked(fs.stat).mockResolvedValue({ size: mockBuffer.length } as any);

      const result = await loadImages(['/test/a.png', '/test/b.jpg']);

      expect(result.images).toHaveLength(2);
      expect(result.errors).toHaveLength(0);
    });

    it('部分加载失败返回错误列表', async () => {
      const mockBuffer = Buffer.from('test');
      vi.mocked(fs.readFile).mockImplementation((path) => {
        if (String(path).includes('good')) {
          return Promise.resolve(mockBuffer);
        }
        const error = new Error('Not found');
        (error as any).code = 'ENOENT';
        return Promise.reject(error);
      });
      vi.mocked(fs.stat).mockResolvedValue({ size: mockBuffer.length } as any);

      const result = await loadImages(['/test/good.png', '/test/bad.png']);

      expect(result.images).toHaveLength(1);
      expect(result.errors).toHaveLength(1);
      expect(result.errors[0].path).toBe('/test/bad.png');
    });

    it('空列表返回空结果', async () => {
      const result = await loadImages([]);

      expect(result.images).toHaveLength(0);
      expect(result.errors).toHaveLength(0);
    });

    it('全部加载失败时 images 为空', async () => {
      const error = new Error('Not found');
      (error as any).code = 'ENOENT';
      vi.mocked(fs.readFile).mockRejectedValue(error);

      const result = await loadImages(['/test/a.png', '/test/b.png']);

      expect(result.images).toHaveLength(0);
      expect(result.errors).toHaveLength(2);
    });

    it('使用自定义工作目录', async () => {
      const mockBuffer = Buffer.from('test');
      vi.mocked(fs.readFile).mockResolvedValue(mockBuffer);
      vi.mocked(fs.stat).mockResolvedValue({ size: mockBuffer.length } as any);

      await loadImages(['./image.png'], '/custom/workdir');

      expect(fs.readFile).toHaveBeenCalledWith(
        expect.stringContaining('custom/workdir')
      );
    });
  });
});
