import { describe, it, expect, vi, beforeEach } from 'vitest';
import { DataSource } from 'typeorm';
import { PrinterService } from '../../src/services/printer.service';
import { FeiePrinterMt } from '../../src/entities/feie-printer.mt.entity';
import type { FeieApiConfig, PrinterDto } from '../../src/types/feie.types';

// Mock dependencies
vi.mock('../../src/services/feie-api.service', () => {
  return {
    FeieApiService: vi.fn().mockImplementation(() => ({
      validatePrinterConfig: vi.fn().mockResolvedValue(true),
      addPrinter: vi.fn().mockResolvedValue({ ret: 0, msg: 'success' }),
      deletePrinter: vi.fn().mockResolvedValue({ ret: 0, msg: 'success' }),
      queryPrinterStatus: vi.fn().mockResolvedValue({ ret: 0, data: [] }),
      batchQueryPrinterStatus: vi.fn().mockResolvedValue({ ret: 0, data: [] })
    }))
  };
});

vi.mock('@d8d/shared-crud', () => {
  return {
    GenericCrudService: vi.fn().mockImplementation(() => ({
      create: vi.fn(),
      findOne: vi.fn(),
      findMany: vi.fn(),
      update: vi.fn(),
      delete: vi.fn()
    }))
  };
});

describe('PrinterService', () => {
  let printerService: PrinterService;
  let mockDataSource: DataSource;
  const mockFeieConfig: FeieApiConfig = {
    baseUrl: 'http://api.feieyun.cn/Api/Open/',
    user: 'test_user',
    ukey: 'test_ukey'
  };

  beforeEach(() => {
    vi.clearAllMocks();

    mockDataSource = {
      getRepository: vi.fn()
    } as unknown as DataSource;

    printerService = new PrinterService(mockDataSource, mockFeieConfig);
  });

  describe('addPrinter', () => {
    it('应该成功添加打印机', async () => {
      const tenantId = 1;
      const printerDto: PrinterDto = {
        printerSn: 'TEST123456',
        printerKey: 'test_key',
        printerName: '测试打印机',
        printerType: '58mm',
        isDefault: false
      };

      const mockPrinter: Partial<FeiePrinterMt> = {
        id: 1,
        tenantId,
        ...printerDto,
        printerStatus: 'ACTIVE',
        isDefault: 0
      };

      // Mock the create method
      (printerService as any).create = vi.fn().mockResolvedValue(mockPrinter);

      const result = await printerService.addPrinter(tenantId, printerDto);

      expect(result).toEqual(mockPrinter);
      expect((printerService as any).create).toHaveBeenCalledWith({
        tenantId,
        printerSn: printerDto.printerSn,
        printerKey: printerDto.printerKey,
        printerName: printerDto.printerName,
        printerType: printerDto.printerType,
        printerStatus: 'ACTIVE',
        isDefault: 0
      });
    });

    it('应该在打印机配置验证失败时抛出错误', async () => {
      const tenantId = 1;
      const printerDto: PrinterDto = {
        printerSn: 'TEST123456',
        printerKey: 'test_key'
      };

      // Mock validatePrinterConfig to return false
      const mockFeieApiService = {
        validatePrinterConfig: vi.fn().mockResolvedValue(false)
      };
      (printerService as any).feieApiService = mockFeieApiService;

      await expect(printerService.addPrinter(tenantId, printerDto))
        .rejects
        .toThrow('打印机配置验证失败，请检查序列号和密钥');
    });

    it('应该在设置为默认打印机时清除其他默认打印机', async () => {
      const tenantId = 1;
      const printerDto: PrinterDto = {
        printerSn: 'TEST123456',
        printerKey: 'test_key',
        isDefault: true
      };

      const mockPrinter: Partial<FeiePrinterMt> = {
        id: 1,
        tenantId,
        ...printerDto,
        printerStatus: 'ACTIVE',
        isDefault: 1
      };

      // Mock the create method
      (printerService as any).create = vi.fn().mockResolvedValue(mockPrinter);
      // Mock clearDefaultPrinter
      (printerService as any).clearDefaultPrinter = vi.fn().mockResolvedValue(undefined);

      await printerService.addPrinter(tenantId, printerDto);

      expect((printerService as any).clearDefaultPrinter).toHaveBeenCalledWith(tenantId);
    });
  });

  describe('updatePrinter', () => {
    it('应该成功更新打印机', async () => {
      const tenantId = 1;
      const printerSn = 'TEST123456';
      const updateDto = {
        printerName: '更新后的打印机名称',
        isDefault: true
      };

      const existingPrinter: Partial<FeiePrinterMt> = {
        id: 1,
        tenantId,
        printerSn,
        printerName: '原打印机名称',
        isDefault: 0
      };

      const updatedPrinter: Partial<FeiePrinterMt> = {
        ...existingPrinter,
        printerName: updateDto.printerName,
        isDefault: 1
      };

      // Mock findOne and update methods
      (printerService as any).findOne = vi.fn().mockResolvedValue(existingPrinter);
      (printerService as any).update = vi.fn().mockResolvedValue(updatedPrinter);
      (printerService as any).clearDefaultPrinter = vi.fn().mockResolvedValue(undefined);

      const result = await printerService.updatePrinter(tenantId, printerSn, updateDto);

      expect(result).toEqual(updatedPrinter);
      expect((printerService as any).clearDefaultPrinter).toHaveBeenCalledWith(tenantId);
    });

    it('应该在打印机不存在时抛出错误', async () => {
      const tenantId = 1;
      const printerSn = 'NONEXISTENT';
      const updateDto = { printerName: '新名称' };

      // Mock findOne to return null
      (printerService as any).findOne = vi.fn().mockResolvedValue(null);

      await expect(printerService.updatePrinter(tenantId, printerSn, updateDto))
        .rejects
        .toThrow('打印机不存在');
    });
  });

  describe('deletePrinter', () => {
    it('应该成功删除打印机', async () => {
      const tenantId = 1;
      const printerSn = 'TEST123456';

      const existingPrinter: Partial<FeiePrinterMt> = {
        id: 1,
        tenantId,
        printerSn
      };

      // Mock findOne and delete methods
      (printerService as any).findOne = vi.fn().mockResolvedValue(existingPrinter);
      (printerService as any).delete = vi.fn().mockResolvedValue(undefined);

      await printerService.deletePrinter(tenantId, printerSn);

      expect((printerService as any).delete).toHaveBeenCalledWith(existingPrinter.id);
    });

    it('应该在打印机不存在时抛出错误', async () => {
      const tenantId = 1;
      const printerSn = 'NONEXISTENT';

      // Mock findOne to return null
      (printerService as any).findOne = vi.fn().mockResolvedValue(null);

      await expect(printerService.deletePrinter(tenantId, printerSn))
        .rejects
        .toThrow('打印机不存在');
    });
  });

  describe('getPrinters', () => {
    it('应该返回打印机列表', async () => {
      const tenantId = 1;
      const mockPrinters: Partial<FeiePrinterMt>[] = [
        { id: 1, tenantId, printerSn: 'PRINTER1', isDefault: 1 },
        { id: 2, tenantId, printerSn: 'PRINTER2', isDefault: 0 }
      ];

      // Mock findMany method
      (printerService as any).findMany = vi.fn().mockResolvedValue(mockPrinters);

      const result = await printerService.getPrinters(tenantId);

      expect(result).toEqual(mockPrinters);
      expect((printerService as any).findMany).toHaveBeenCalledWith({
        where: { tenantId },
        order: { isDefault: 'DESC', createdAt: 'DESC' }
      });
    });
  });

  describe('getDefaultPrinter', () => {
    it('应该返回默认打印机', async () => {
      const tenantId = 1;
      const mockPrinter: Partial<FeiePrinterMt> = {
        id: 1,
        tenantId,
        printerSn: 'PRINTER1',
        isDefault: 1
      };

      // Mock findOne method
      (printerService as any).findOne = vi.fn().mockResolvedValue(mockPrinter);

      const result = await printerService.getDefaultPrinter(tenantId);

      expect(result).toEqual(mockPrinter);
      expect((printerService as any).findOne).toHaveBeenCalledWith({
        where: { tenantId, isDefault: 1 }
      });
    });

    it('应该在无默认打印机时返回null', async () => {
      const tenantId = 1;

      // Mock findOne to return null
      (printerService as any).findOne = vi.fn().mockResolvedValue(null);

      const result = await printerService.getDefaultPrinter(tenantId);

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