import { describe, it, expect, vi, beforeEach } from 'vitest';
import { invoke } from '@tauri-apps/api/core';
import { AiClassificationService } from '../aiClassificationService';
import {
  AiClassification,
  CreateAiClassificationRequest,
  UpdateAiClassificationRequest,
  AiClassificationQuery,
  AiClassificationPreview,
} from '../../types/aiClassification';

// Mock Tauri invoke
vi.mock('@tauri-apps/api/core', () => ({
  invoke: vi.fn(),
}));

const mockInvoke = vi.mocked(invoke);

describe('AiClassificationService', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  const mockClassification: AiClassification = {
    id: 'test-id',
    name: '全身',
    prompt_text: '头顶到脚底完整入镜，肢体可见度≥90%',
    description: '全身分类描述',
    is_active: true,
    sort_order: 1,
    created_at: '2024-01-01T00:00:00Z',
    updated_at: '2024-01-01T00:00:00Z',
  };

  describe('createClassification', () => {
    it('should create a classification successfully', async () => {
      const request: CreateAiClassificationRequest = {
        name: '全身',
        prompt_text: '头顶到脚底完整入镜，肢体可见度≥90%',
        description: '全身分类描述',
        sort_order: 1,
      };

      mockInvoke.mockResolvedValue(mockClassification);

      const result = await AiClassificationService.createClassification(request);

      expect(mockInvoke).toHaveBeenCalledWith('create_ai_classification', { request });
      expect(result).toEqual(mockClassification);
    });

    it('should handle creation errors', async () => {
      const request: CreateAiClassificationRequest = {
        name: '全身',
        prompt_text: '头顶到脚底完整入镜',
      };

      mockInvoke.mockRejectedValue('创建失败');

      await expect(AiClassificationService.createClassification(request))
        .rejects.toThrow('创建失败');
    });
  });

  describe('getAllClassifications', () => {
    it('should get all classifications successfully', async () => {
      const classifications = [mockClassification];
      mockInvoke.mockResolvedValue(classifications);

      const result = await AiClassificationService.getAllClassifications();

      expect(mockInvoke).toHaveBeenCalledWith('get_all_ai_classifications', { query: undefined });
      expect(result).toEqual(classifications);
    });

    it('should get classifications with query parameters', async () => {
      const query: AiClassificationQuery = {
        active_only: true,
        sort_by: 'name',
        sort_order: 'ASC',
      };
      const classifications = [mockClassification];
      mockInvoke.mockResolvedValue(classifications);

      const result = await AiClassificationService.getAllClassifications(query);

      expect(mockInvoke).toHaveBeenCalledWith('get_all_ai_classifications', { query });
      expect(result).toEqual(classifications);
    });

    it('should handle get all errors', async () => {
      mockInvoke.mockRejectedValue('获取失败');

      await expect(AiClassificationService.getAllClassifications())
        .rejects.toThrow('获取失败');
    });
  });

  describe('getClassificationById', () => {
    it('should get classification by id successfully', async () => {
      mockInvoke.mockResolvedValue(mockClassification);

      const result = await AiClassificationService.getClassificationById('test-id');

      expect(mockInvoke).toHaveBeenCalledWith('get_ai_classification_by_id', { id: 'test-id' });
      expect(result).toEqual(mockClassification);
    });

    it('should return null when classification not found', async () => {
      mockInvoke.mockResolvedValue(null);

      const result = await AiClassificationService.getClassificationById('non-existent');

      expect(result).toBeNull();
    });
  });

  describe('updateClassification', () => {
    it('should update classification successfully', async () => {
      const request: UpdateAiClassificationRequest = {
        name: '全身更新',
        prompt_text: '更新的提示词',
      };
      const updatedClassification = { ...mockClassification, ...request };
      mockInvoke.mockResolvedValue(updatedClassification);

      const result = await AiClassificationService.updateClassification('test-id', request);

      expect(mockInvoke).toHaveBeenCalledWith('update_ai_classification', { 
        id: 'test-id', 
        request 
      });
      expect(result).toEqual(updatedClassification);
    });

    it('should handle update errors', async () => {
      const request: UpdateAiClassificationRequest = { name: '新名称' };
      mockInvoke.mockRejectedValue('更新失败');

      await expect(AiClassificationService.updateClassification('test-id', request))
        .rejects.toThrow('更新失败');
    });
  });

  describe('deleteClassification', () => {
    it('should delete classification successfully', async () => {
      mockInvoke.mockResolvedValue(true);

      const result = await AiClassificationService.deleteClassification('test-id');

      expect(mockInvoke).toHaveBeenCalledWith('delete_ai_classification', { id: 'test-id' });
      expect(result).toBe(true);
    });

    it('should return false when classification not found', async () => {
      mockInvoke.mockResolvedValue(false);

      const result = await AiClassificationService.deleteClassification('non-existent');

      expect(result).toBe(false);
    });
  });

  describe('getClassificationCount', () => {
    it('should get classification count successfully', async () => {
      mockInvoke.mockResolvedValue(5);

      const result = await AiClassificationService.getClassificationCount();

      expect(mockInvoke).toHaveBeenCalledWith('get_ai_classification_count', { 
        active_only: undefined 
      });
      expect(result).toBe(5);
    });

    it('should get active classification count', async () => {
      mockInvoke.mockResolvedValue(3);

      const result = await AiClassificationService.getClassificationCount(true);

      expect(mockInvoke).toHaveBeenCalledWith('get_ai_classification_count', { 
        active_only: true 
      });
      expect(result).toBe(3);
    });
  });

  describe('generatePreview', () => {
    it('should generate preview successfully', async () => {
      const preview: AiClassificationPreview = {
        classifications: [mockClassification],
        full_prompt: '完整的提示词内容...',
      };
      mockInvoke.mockResolvedValue(preview);

      const result = await AiClassificationService.generatePreview();

      expect(mockInvoke).toHaveBeenCalledWith('generate_ai_classification_preview');
      expect(result).toEqual(preview);
    });

    it('should handle preview generation errors', async () => {
      mockInvoke.mockRejectedValue('生成预览失败');

      await expect(AiClassificationService.generatePreview())
        .rejects.toThrow('生成预览失败');
    });
  });

  describe('updateSortOrders', () => {
    it('should update sort orders successfully', async () => {
      const updates = [
        { id: 'id1', sort_order: 1 },
        { id: 'id2', sort_order: 2 },
      ];
      const updatedClassifications = [mockClassification];
      mockInvoke.mockResolvedValue(updatedClassifications);

      const result = await AiClassificationService.updateSortOrders(updates);

      expect(mockInvoke).toHaveBeenCalledWith('update_ai_classification_sort_orders', { 
        updates: [['id1', 1], ['id2', 2]]
      });
      expect(result).toEqual(updatedClassifications);
    });
  });

  describe('toggleClassificationStatus', () => {
    it('should toggle classification status successfully', async () => {
      const toggledClassification = { ...mockClassification, is_active: false };
      mockInvoke.mockResolvedValue(toggledClassification);

      const result = await AiClassificationService.toggleClassificationStatus('test-id');

      expect(mockInvoke).toHaveBeenCalledWith('toggle_ai_classification_status', { 
        id: 'test-id' 
      });
      expect(result).toEqual(toggledClassification);
    });
  });

  describe('validateClassificationName', () => {
    it('should validate classification name successfully', async () => {
      mockInvoke.mockResolvedValue(true);

      const result = await AiClassificationService.validateClassificationName('新名称');

      expect(mockInvoke).toHaveBeenCalledWith('validate_ai_classification_name', { 
        name: '新名称',
        exclude_id: undefined
      });
      expect(result).toBe(true);
    });

    it('should validate with exclude id', async () => {
      mockInvoke.mockResolvedValue(false);

      const result = await AiClassificationService.validateClassificationName('已存在', 'exclude-id');

      expect(mockInvoke).toHaveBeenCalledWith('validate_ai_classification_name', { 
        name: '已存在',
        exclude_id: 'exclude-id'
      });
      expect(result).toBe(false);
    });
  });

  describe('Safe methods', () => {
    it('should return success response for createClassificationSafe', async () => {
      const request: CreateAiClassificationRequest = {
        name: '测试',
        prompt_text: '测试提示词',
      };
      mockInvoke.mockResolvedValue(mockClassification);

      const result = await AiClassificationService.createClassificationSafe(request);

      expect(result.success).toBe(true);
      expect(result.data).toEqual(mockClassification);
      expect(result.error).toBeUndefined();
    });

    it('should return error response for createClassificationSafe', async () => {
      const request: CreateAiClassificationRequest = {
        name: '测试',
        prompt_text: '测试提示词',
      };
      mockInvoke.mockRejectedValue('创建失败');

      const result = await AiClassificationService.createClassificationSafe(request);

      expect(result.success).toBe(false);
      expect(result.data).toBeUndefined();
      expect(result.error).toBe('创建失败');
    });
  });

  describe('Utility methods', () => {
    it('should get active classifications', async () => {
      const classifications = [mockClassification];
      mockInvoke.mockResolvedValue(classifications);

      const result = await AiClassificationService.getActiveClassifications();

      expect(mockInvoke).toHaveBeenCalledWith('get_all_ai_classifications', {
        query: {
          active_only: true,
          sort_by: 'sort_order',
          sort_order: 'ASC',
        }
      });
      expect(result).toEqual(classifications);
    });

    it('should reorder classifications', async () => {
      const orderedIds = ['id1', 'id2', 'id3'];
      const updatedClassifications = [mockClassification];
      mockInvoke.mockResolvedValue(updatedClassifications);

      const result = await AiClassificationService.reorderClassifications(orderedIds);

      expect(mockInvoke).toHaveBeenCalledWith('update_ai_classification_sort_orders', {
        updates: [['id1', 1], ['id2', 2], ['id3', 3]]
      });
      expect(result).toEqual(updatedClassifications);
    });

    it('should duplicate classification', async () => {
      // Mock getting original classification
      mockInvoke.mockResolvedValueOnce(mockClassification);
      // Mock creating duplicate
      const duplicatedClassification = { 
        ...mockClassification, 
        id: 'new-id',
        name: '全身 (副本)' 
      };
      mockInvoke.mockResolvedValueOnce(duplicatedClassification);

      const result = await AiClassificationService.duplicateClassification('test-id');

      expect(mockInvoke).toHaveBeenCalledTimes(2);
      expect(mockInvoke).toHaveBeenNthCalledWith(1, 'get_ai_classification_by_id', { 
        id: 'test-id' 
      });
      expect(mockInvoke).toHaveBeenNthCalledWith(2, 'create_ai_classification', {
        request: {
          name: '全身 (副本)',
          prompt_text: mockClassification.prompt_text,
          description: mockClassification.description,
          sort_order: mockClassification.sort_order + 1,
        }
      });
      expect(result).toEqual(duplicatedClassification);
    });

    it('should handle duplicate classification when original not found', async () => {
      mockInvoke.mockResolvedValue(null);

      await expect(AiClassificationService.duplicateClassification('non-existent'))
        .rejects.toThrow('要复制的分类不存在');
    });
  });
});
