import { Test, TestingModule } from '@nestjs/testing';
import { OperationAgentService } from './OperationAgentService';
import { getRepositoryToken } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Store } from '../../entities/Store';
import { PlatformAdapterFactory } from './adapters/PlatformAdapterFactory';
import { AmazonAdapter } from './adapters/AmazonAdapter';
import { ShopeeAdapter } from './adapters/ShopeeAdapter';
import { AliExpressAdapter } from './adapters/AliExpressAdapter';
import { TikTokAdapter } from './adapters/TikTokAdapter';
import { EbayAdapter } from './adapters/EbayAdapter';
import { GenericAdapter } from './adapters/GenericAdapter';
import { StoreBindingDto } from '../../api/dto/StoreBindingDto';
import { StoreStatus } from '../../types/enums/StoreStatus';
import { EventEmitter2 } from '@nestjs/event-emitter';

// 模拟Store实体
class MockStore {
  id: string;
  merchantId: string;
  name: string;
  platform: string;
  platformShopId: string;
  description: string;
  status: StoreStatus;
  created_at: Date;
  updated_at: Date;
}

// 模拟Repository
class MockRepository {
  findOne = jest.fn();
  find = jest.fn();
  create = jest.fn();
  save = jest.fn();
  findOneBy = jest.fn();
}

// 模拟平台适配器
class MockPlatformAdapter {
  authorize = jest.fn();
  getShopInfo = jest.fn();
  getProducts = jest.fn();
  getOrders = jest.fn();
  updateProductPrice = jest.fn();
  updateProductStock = jest.fn();
  listProduct = jest.fn();
  delistProduct = jest.fn();
  getApiStatus = jest.fn();
}

// 模拟平台适配器工厂
class MockPlatformAdapterFactory {
  createAdapter = jest.fn();
  getSupportedPlatforms = jest.fn();
  isPlatformSupported = jest.fn();
}

describe('OperationAgentService', () => {
  let service: OperationAgentService;
  let storeRepository: Repository<Store>;
  let platformAdapterFactory: PlatformAdapterFactory;
  let eventEmitter: EventEmitter2;
  let mockAdapter: MockPlatformAdapter;

  beforeEach(async () => {
    mockAdapter = new MockPlatformAdapter();

    const module: TestingModule = await Test.createTestingModule({
      providers: [
        OperationAgentService,
        {
          provide: getRepositoryToken(Store),
          useClass: MockRepository,
        },
        {
          provide: PlatformAdapterFactory,
          useValue: {
            createAdapter: jest.fn().mockReturnValue(mockAdapter),
          },
        },
        {
          provide: EventEmitter2,
          useValue: {
            emit: jest.fn(),
          },
        },
        {
          provide: AmazonAdapter,
          useValue: new MockPlatformAdapter(),
        },
        {
          provide: ShopeeAdapter,
          useValue: new MockPlatformAdapter(),
        },
        {
          provide: AliExpressAdapter,
          useValue: new MockPlatformAdapter(),
        },
        {
          provide: TikTokAdapter,
          useValue: new MockPlatformAdapter(),
        },
        {
          provide: EbayAdapter,
          useValue: new MockPlatformAdapter(),
        },
        {
          provide: GenericAdapter,
          useValue: new MockPlatformAdapter(),
        },
      ],
    }).compile();

    service = module.get<OperationAgentService>(OperationAgentService);
    storeRepository = module.get<Repository<Store>>(getRepositoryToken(Store));
    platformAdapterFactory = module.get<PlatformAdapterFactory>(PlatformAdapterFactory);
    eventEmitter = module.get<EventEmitter2>(EventEmitter2);
  });

  afterEach(() => {
    jest.clearAllMocks();
  });

  describe('bindStore', () => {
    it('should bind a new store successfully', async () => {
      // 准备测试数据
      const dto: StoreBindingDto = {
        merchantId: 'merchant-1',
        platform: 'amazon',
        platformShopId: 'amazon-shop-1',
        name: 'Test Store',
        description: 'Test Store Description',
        authInfo: {
          accessKey: 'test-access-key',
          secretKey: 'test-secret-key',
          sellerId: 'test-seller-id',
          marketplaceId: 'test-marketplace-id',
        },
      };

      // 模拟方法调用
      (storeRepository.findOne as jest.Mock).mockResolvedValue(null);
      (storeRepository.create as jest.Mock).mockReturnValue({
        id: 'store-1',
        ...dto,
        status: StoreStatus.PENDING,
        created_at: new Date(),
        updated_at: new Date(),
      });
      (storeRepository.save as jest.Mock).mockResolvedValueOnce({
        id: 'store-1',
        ...dto,
        status: StoreStatus.PENDING,
        created_at: new Date(),
        updated_at: new Date(),
      }).mockResolvedValueOnce({
        id: 'store-1',
        ...dto,
        status: StoreStatus.ACTIVE,
        created_at: new Date(),
        updated_at: new Date(),
      });
      mockAdapter.authorize.mockResolvedValue(true);
      mockAdapter.getShopInfo.mockResolvedValue({
        id: 'amazon-shop-1',
        name: 'Test Store',
        description: 'Test Store Description',
        status: 'active',
        createdAt: new Date(),
        updatedAt: new Date(),
      });

      // 执行测试
      const result = await service.bindStore(dto);

      // 验证结果
      expect(result.status).toBe(StoreStatus.ACTIVE);
      expect(storeRepository.findOne).toHaveBeenCalledWith({
        where: {
          merchantId: dto.merchantId,
          platform: dto.platform,
          platformShopId: dto.platformShopId,
        },
      });
      expect(storeRepository.create).toHaveBeenCalled();
      expect(storeRepository.save).toHaveBeenCalledTimes(2);
      expect(mockAdapter.authorize).toHaveBeenCalledWith(dto.authInfo);
      expect(mockAdapter.getShopInfo).toHaveBeenCalled();
      expect(eventEmitter.emit).toHaveBeenCalledWith('operation_agent.store.bound', expect.any(Object));
    });

    it('should return existing store if already bound', async () => {
      // 准备测试数据
      const dto: StoreBindingDto = {
        merchantId: 'merchant-1',
        platform: 'amazon',
        platformShopId: 'amazon-shop-1',
        name: 'Test Store',
        description: 'Test Store Description',
        authInfo: {
          accessKey: 'test-access-key',
          secretKey: 'test-secret-key',
          sellerId: 'test-seller-id',
          marketplaceId: 'test-marketplace-id',
        },
      };

      const existingStore = {
        id: 'store-1',
        ...dto,
        status: StoreStatus.ACTIVE,
        created_at: new Date(),
        updated_at: new Date(),
      };

      // 模拟方法调用
      (storeRepository.findOne as jest.Mock).mockResolvedValue(existingStore);

      // 执行测试
      const result = await service.bindStore(dto);

      // 验证结果
      expect(result).toEqual(existingStore);
      expect(storeRepository.findOne).toHaveBeenCalledWith({
        where: {
          merchantId: dto.merchantId,
          platform: dto.platform,
          platformShopId: dto.platformShopId,
        },
      });
      expect(storeRepository.create).not.toHaveBeenCalled();
    });

    it('should handle binding failure', async () => {
      // 准备测试数据
      const dto: StoreBindingDto = {
        merchantId: 'merchant-1',
        platform: 'amazon',
        platformShopId: 'amazon-shop-1',
        name: 'Test Store',
        description: 'Test Store Description',
        authInfo: {
          accessKey: 'test-access-key',
          secretKey: 'test-secret-key',
          sellerId: 'test-seller-id',
          marketplaceId: 'test-marketplace-id',
        },
      };

      // 模拟方法调用
      (storeRepository.findOne as jest.Mock).mockResolvedValue(null);
      (storeRepository.create as jest.Mock).mockReturnValue({
        id: 'store-1',
        ...dto,
        status: StoreStatus.PENDING,
        created_at: new Date(),
        updated_at: new Date(),
      });
      (storeRepository.save as jest.Mock).mockResolvedValueOnce({
        id: 'store-1',
        ...dto,
        status: StoreStatus.PENDING,
        created_at: new Date(),
        updated_at: new Date(),
      }).mockResolvedValueOnce({
        id: 'store-1',
        ...dto,
        status: StoreStatus.INACTIVE,
        created_at: new Date(),
        updated_at: new Date(),
      });
      mockAdapter.authorize.mockRejectedValue(new Error('Authorization failed'));

      // 执行测试
      await expect(service.bindStore(dto)).rejects.toThrow('Authorization failed');

      // 验证结果
      expect(storeRepository.save).toHaveBeenCalledTimes(2);
      expect(eventEmitter.emit).toHaveBeenCalledWith('operation_agent.store.bind.failed', expect.any(Object));
    });
  });

  describe('syncProducts', () => {
    it('should sync products successfully', async () => {
      // 准备测试数据
      const storeId = 'store-1';
      const store = {
        id: storeId,
        merchantId: 'merchant-1',
        name: 'Test Store',
        platform: 'amazon',
        platformShopId: 'amazon-shop-1',
        status: StoreStatus.ACTIVE,
        created_at: new Date(),
        updated_at: new Date(),
      };

      const products = [
        {
          id: 'product-1',
          name: 'Product 1',
          sku: 'PROD-1',
          price: 100,
          stock: 10,
          description: 'Product 1 Description',
          images: ['image1.jpg'],
          categories: ['Category 1'],
          attributes: {},
          createdAt: new Date(),
          updatedAt: new Date(),
        },
      ];

      // 模拟方法调用
      (storeRepository.findOneBy as jest.Mock).mockResolvedValue(store);
      mockAdapter.getProducts.mockResolvedValue(products);

      // 执行测试
      const result = await service.syncProducts(storeId);

      // 验证结果
      expect(result.success).toBe(true);
      expect(result.count).toBe(products.length);
      expect(storeRepository.findOneBy).toHaveBeenCalledWith({ id: storeId });
      expect(mockAdapter.getProducts).toHaveBeenCalled();
      expect(eventEmitter.emit).toHaveBeenCalledWith('operation_agent.products.synced', {
        storeId,
        count: products.length,
      });
    });

    it('should throw error if store not found', async () => {
      // 准备测试数据
      const storeId = 'store-1';

      // 模拟方法调用
      (storeRepository.findOneBy as jest.Mock).mockResolvedValue(null);

      // 执行测试
      await expect(service.syncProducts(storeId)).rejects.toThrow('店铺不存在');

      // 验证结果
      expect(storeRepository.findOneBy).toHaveBeenCalledWith({ id: storeId });
    });

    it('should throw error if store status is not active', async () => {
      // 准备测试数据
      const storeId = 'store-1';
      const store = {
        id: storeId,
        merchantId: 'merchant-1',
        name: 'Test Store',
        platform: 'amazon',
        platformShopId: 'amazon-shop-1',
        status: StoreStatus.INACTIVE,
        created_at: new Date(),
        updated_at: new Date(),
      };

      // 模拟方法调用
      (storeRepository.findOneBy as jest.Mock).mockResolvedValue(store);

      // 执行测试
      await expect(service.syncProducts(storeId)).rejects.toThrow('店铺状态异常，无法同步商品');

      // 验证结果
      expect(storeRepository.findOneBy).toHaveBeenCalledWith({ id: storeId });
    });
  });

  describe('syncOrders', () => {
    it('should sync orders successfully', async () => {
      // 准备测试数据
      const storeId = 'store-1';
      const store = {
        id: storeId,
        merchantId: 'merchant-1',
        name: 'Test Store',
        platform: 'amazon',
        platformShopId: 'amazon-shop-1',
        status: StoreStatus.ACTIVE,
        created_at: new Date(),
        updated_at: new Date(),
      };

      const orders = [
        {
          id: 'order-1',
          customerId: 'customer-1',
          totalAmount: 200,
          status: 'shipped',
          items: [
            {
              productId: 'product-1',
              quantity: 1,
              price: 200,
            },
          ],
          shippingAddress: {
            name: 'Customer 1',
            address: '123 Main St',
            city: 'New York',
            state: 'NY',
            zip: '10001',
            country: 'US',
          },
          paymentMethod: 'credit_card',
          createdAt: new Date(),
          updatedAt: new Date(),
        },
      ];

      // 模拟方法调用
      (storeRepository.findOneBy as jest.Mock).mockResolvedValue(store);
      mockAdapter.getOrders.mockResolvedValue(orders);

      // 执行测试
      const result = await service.syncOrders(storeId);

      // 验证结果
      expect(result.success).toBe(true);
      expect(result.count).toBe(orders.length);
      expect(storeRepository.findOneBy).toHaveBeenCalledWith({ id: storeId });
      expect(mockAdapter.getOrders).toHaveBeenCalled();
      expect(eventEmitter.emit).toHaveBeenCalledWith('operation_agent.orders.synced', {
        storeId,
        count: orders.length,
      });
    });
  });

  describe('updateProductPrice', () => {
    it('should update product price successfully', async () => {
      // 准备测试数据
      const storeId = 'store-1';
      const productId = 'product-1';
      const price = 150;
      const store = {
        id: storeId,
        merchantId: 'merchant-1',
        name: 'Test Store',
        platform: 'amazon',
        platformShopId: 'amazon-shop-1',
        status: StoreStatus.ACTIVE,
        created_at: new Date(),
        updated_at: new Date(),
      };

      // 模拟方法调用
      (storeRepository.findOneBy as jest.Mock).mockResolvedValue(store);
      mockAdapter.updateProductPrice.mockResolvedValue(true);

      // 执行测试
      const result = await service.updateProductPrice(storeId, productId, price);

      // 验证结果
      expect(result).toBe(true);
      expect(storeRepository.findOneBy).toHaveBeenCalledWith({ id: storeId });
      expect(mockAdapter.updateProductPrice).toHaveBeenCalledWith(productId, price);
      expect(eventEmitter.emit).toHaveBeenCalledWith('operation_agent.product.price.updated', {
        storeId,
        productId,
        price,
      });
    });
  });

  describe('getStores', () => {
    it('should get stores for a merchant', async () => {
      // 准备测试数据
      const merchantId = 'merchant-1';
      const stores = [
        {
          id: 'store-1',
          merchantId: merchantId,
          name: 'Store 1',
          platform: 'amazon',
          platformShopId: 'amazon-shop-1',
          status: StoreStatus.ACTIVE,
          created_at: new Date(),
          updated_at: new Date(),
        },
      ];

      // 模拟方法调用
      (storeRepository.find as jest.Mock).mockResolvedValue(stores);

      // 执行测试
      const result = await service.getStores(merchantId);

      // 验证结果
      expect(result).toEqual(stores);
      expect(storeRepository.find).toHaveBeenCalledWith({ where: { merchantId } });
    });
  });

  describe('getStore', () => {
    it('should get store by id', async () => {
      // 准备测试数据
      const storeId = 'store-1';
      const store = {
        id: storeId,
        merchantId: 'merchant-1',
        name: 'Test Store',
        platform: 'amazon',
        platformShopId: 'amazon-shop-1',
        status: StoreStatus.ACTIVE,
        created_at: new Date(),
        updated_at: new Date(),
      };

      // 模拟方法调用
      (storeRepository.findOneBy as jest.Mock).mockResolvedValue(store);

      // 执行测试
      const result = await service.getStore(storeId);

      // 验证结果
      expect(result).toEqual(store);
      expect(storeRepository.findOneBy).toHaveBeenCalledWith({ id: storeId });
    });

    it('should throw error if store not found', async () => {
      // 准备测试数据
      const storeId = 'store-1';

      // 模拟方法调用
      (storeRepository.findOneBy as jest.Mock).mockResolvedValue(null);

      // 执行测试
      await expect(service.getStore(storeId)).rejects.toThrow('店铺不存在');

      // 验证结果
      expect(storeRepository.findOneBy).toHaveBeenCalledWith({ id: storeId });
    });
  });

  describe('deactivateStore', () => {
    it('should deactivate store successfully', async () => {
      // 准备测试数据
      const storeId = 'store-1';
      const store = {
        id: storeId,
        merchantId: 'merchant-1',
        name: 'Test Store',
        platform: 'amazon',
        platformShopId: 'amazon-shop-1',
        status: StoreStatus.ACTIVE,
        created_at: new Date(),
        updated_at: new Date(),
      };

      const updatedStore = {
        ...store,
        status: StoreStatus.INACTIVE,
      };

      // 模拟方法调用
      (storeRepository.findOneBy as jest.Mock).mockResolvedValue(store);
      (storeRepository.save as jest.Mock).mockResolvedValue(updatedStore);

      // 执行测试
      const result = await service.deactivateStore(storeId);

      // 验证结果
      expect(result.status).toBe(StoreStatus.INACTIVE);
      expect(storeRepository.findOneBy).toHaveBeenCalledWith({ id: storeId });
      expect(storeRepository.save).toHaveBeenCalledWith(updatedStore);
      expect(eventEmitter.emit).toHaveBeenCalledWith('operation_agent.store.deactivated', updatedStore);
    });
  });

  describe('reactivateStore', () => {
    it('should reactivate store successfully', async () => {
      // 准备测试数据
      const storeId = 'store-1';
      const store = {
        id: storeId,
        merchantId: 'merchant-1',
        name: 'Test Store',
        platform: 'amazon',
        platformShopId: 'amazon-shop-1',
        status: StoreStatus.INACTIVE,
        created_at: new Date(),
        updated_at: new Date(),
      };

      const updatedStore = {
        ...store,
        status: StoreStatus.ACTIVE,
      };

      // 模拟方法调用
      (storeRepository.findOneBy as jest.Mock).mockResolvedValue(store);
      (storeRepository.save as jest.Mock).mockResolvedValue(updatedStore);

      // 执行测试
      const result = await service.reactivateStore(storeId);

      // 验证结果
      expect(result.status).toBe(StoreStatus.ACTIVE);
      expect(storeRepository.findOneBy).toHaveBeenCalledWith({ id: storeId });
      expect(storeRepository.save).toHaveBeenCalledWith(updatedStore);
      expect(eventEmitter.emit).toHaveBeenCalledWith('operation_agent.store.activated', updatedStore);
    });
  });
});
