import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
import { testClient } from 'hono/testing';
import { IntegrationTestDatabase, setupIntegrationDatabaseHooksWithEntities } from '@d8d/shared-test-util';
import { JWTUtil } from '@d8d/shared-utils';
import { UserEntityMt, RoleMt } from '@d8d/user-module-mt';
import { FileMt } from '@d8d/file-module-mt';
import { advertisementRoutes } from '../../src/routes';
import { Advertisement } from '../../src/entities/advertisement.entity';
import { AdvertisementType } from '../../src/entities/advertisement-type.entity';

// 设置集成测试钩子
setupIntegrationDatabaseHooksWithEntities([UserEntityMt, FileMt, RoleMt, Advertisement, AdvertisementType])

describe('多租户广告管理API集成测试', () => {
  let client: ReturnType<typeof testClient<typeof advertisementRoutes>>;
  let testToken: string;
  let testUser: UserEntityMt;
  let testAdvertisementType: AdvertisementType;

  beforeEach(async () => {
    // 创建测试客户端
    client = testClient(advertisementRoutes);

    // 获取数据源
    const dataSource = await IntegrationTestDatabase.getDataSource();

    // 创建测试用户
    const userRepository = dataSource.getRepository(UserEntityMt);
    testUser = userRepository.create({
      username: `test_user_${Date.now()}`,
      password: 'test_password',
      nickname: '测试用户',
      registrationSource: 'web',
      tenantId: 1
    });
    await userRepository.save(testUser);

    // 创建测试广告类型
    const advertisementTypeRepository = dataSource.getRepository(AdvertisementType);
    testAdvertisementType = advertisementTypeRepository.create({
      name: '首页轮播',
      code: 'home_banner',
      remark: '用于首页轮播图展示',
      status: 1,
      tenantId: 1
    });
    await advertisementTypeRepository.save(testAdvertisementType);

    // 生成测试用户的token
    testToken = JWTUtil.generateToken({
      id: testUser.id,
      username: testUser.username,
      roles: [{name:'user'}]
    });
  });

  describe('GET /advertisements', () => {
    it('应该返回广告列表', async () => {
      const response = await client.index.$get({
        query: {}
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      console.debug('广告列表响应状态:', response.status);
      expect(response.status).toBe(200);

      if (response.status === 200) {
        const data = await response.json();
        expect(data).toHaveProperty('data');
        expect(Array.isArray(data.data)).toBe(true);
      }
    });

    it('应该拒绝未认证用户的访问', async () => {
      const response = await client.index.$get({
        query: {}
      });
      expect(response.status).toBe(401);
    });
  });

  describe('POST /advertisements', () => {
    it('应该成功创建广告', async () => {
      const createData = {
        title: '测试广告',
        typeId: testAdvertisementType.id,
        code: 'test_ad',
        url: 'https://example.com',
        sort: 10,
        status: 1,
        actionType: 1
      };

      const response = await client.index.$post({
        json: createData
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      console.debug('创建广告响应状态:', response.status);
      expect(response.status).toBe(201);

      if (response.status === 201) {
        const data = await response.json();
        expect(data).toHaveProperty('id');
        expect(data.title).toBe(createData.title);
        expect(data.code).toBe(createData.code);
        expect(data.status).toBe(createData.status);
      }
    });

    it('应该验证创建广告的必填字段', async () => {
      const invalidData = {
        // 缺少必填字段
        title: '',
        typeId: 0,
        code: '',
        url: 'https://example.com'
      };

      const response = await client.index.$post({
        json: invalidData
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      expect(response.status).toBe(400);
    });
  });

  describe('GET /advertisements/:id', () => {
    it('应该返回指定广告的详情', async () => {
      // 先创建一个广告
      const dataSource = await IntegrationTestDatabase.getDataSource();
      const advertisementRepository = dataSource.getRepository(Advertisement);
      const testAdvertisement = advertisementRepository.create({
        title: '测试广告详情',
        typeId: testAdvertisementType.id,
        code: 'test_ad_detail',
        url: 'https://example.com',
        sort: 5,
        status: 1,
        actionType: 1,
        createdBy: testUser.id,
        tenantId: 1
      });
      await advertisementRepository.save(testAdvertisement);

      const response = await client[':id'].$get({
        param: { id: testAdvertisement.id }
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      console.debug('广告详情响应状态:', response.status);
      expect(response.status).toBe(200);

      if (response.status === 200) {
        const data = await response.json();
        expect(data.id).toBe(testAdvertisement.id);
        expect(data.title).toBe(testAdvertisement.title);
        expect(data.code).toBe(testAdvertisement.code);
      }
    });

    it('应该处理不存在的广告', async () => {
      const response = await client[':id'].$get({
        param: { id: 999999 }
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      expect(response.status).toBe(404);
    });
  });

  describe('PUT /advertisements/:id', () => {
    it('应该成功更新广告', async () => {
      // 先创建一个广告
      const dataSource = await IntegrationTestDatabase.getDataSource();
      const advertisementRepository = dataSource.getRepository(Advertisement);
      const testAdvertisement = advertisementRepository.create({
        title: '原始广告',
        typeId: testAdvertisementType.id,
        code: 'original_ad',
        url: 'https://example.com',
        sort: 5,
        status: 1,
        actionType: 1,
        createdBy: testUser.id,
        tenantId: 1
      });
      await advertisementRepository.save(testAdvertisement);

      const updateData = {
        title: '更新后的广告',
        code: 'updated_ad',
        sort: 15
      };

      const response = await client[':id'].$put({
        param: { id: testAdvertisement.id },
        json: updateData
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      console.debug('更新广告响应状态:', response.status);
      expect(response.status).toBe(200);

      if (response.status === 200) {
        const data = await response.json();
        expect(data.title).toBe(updateData.title);
        expect(data.code).toBe(updateData.code);
        expect(data.sort).toBe(updateData.sort);
      }
    });
  });

  describe('DELETE /advertisements/:id', () => {
    it('应该成功删除广告', async () => {
      // 先创建一个广告
      const dataSource = await IntegrationTestDatabase.getDataSource();
      const advertisementRepository = dataSource.getRepository(Advertisement);
      const testAdvertisement = advertisementRepository.create({
        title: '待删除广告',
        typeId: testAdvertisementType.id,
        code: 'delete_ad',
        url: 'https://example.com',
        sort: 5,
        status: 1,
        actionType: 1,
        createdBy: testUser.id,
        tenantId: 1
      });
      await advertisementRepository.save(testAdvertisement);

      const response = await client[':id'].$delete({
        param: { id: testAdvertisement.id }
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      console.debug('删除广告响应状态:', response.status);
      expect(response.status).toBe(204);

      // 验证广告确实被删除
      const deletedAdvertisement = await advertisementRepository.findOne({
        where: { id: testAdvertisement.id }
      });
      expect(deletedAdvertisement).toBeNull();
    });
  });

  describe('租户数据隔离测试', () => {
    it('应该确保租户只能访问自己的数据', async () => {
      const dataSource = await IntegrationTestDatabase.getDataSource();
      const advertisementRepository = dataSource.getRepository(Advertisement);

      // 创建租户1的广告
      const tenant1Advertisement = advertisementRepository.create({
        title: '租户1广告',
        typeId: testAdvertisementType.id,
        code: 'tenant1_ad',
        url: 'https://example.com',
        sort: 1,
        status: 1,
        actionType: 1,
        createdBy: testUser.id,
        tenantId: 1
      });
      await advertisementRepository.save(tenant1Advertisement);

      // 创建租户2的广告
      const tenant2Advertisement = advertisementRepository.create({
        title: '租户2广告',
        typeId: testAdvertisementType.id,
        code: 'tenant2_ad',
        url: 'https://example.com',
        sort: 1,
        status: 1,
        actionType: 1,
        createdBy: testUser.id,
        tenantId: 2
      });
      await advertisementRepository.save(tenant2Advertisement);

      // 测试租户1只能看到自己的广告
      const response = await client.index.$get({
        query: {}
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      expect(response.status).toBe(200);
      const data = await response.json();

      // 验证返回的数据只包含租户1的广告
      if ('data' in data) {
        const tenant1Ads = data.data.filter((ad: any) => ad.tenantId === 1);
        const tenant2Ads = data.data.filter((ad: any) => ad.tenantId === 2);

        expect(tenant1Ads.length).toBeGreaterThan(0);
        expect(tenant2Ads.length).toBe(0); // 租户1不应该看到租户2的广告
      }
    });

    it('应该防止跨租户数据访问', async () => {
      const dataSource = await IntegrationTestDatabase.getDataSource();
      const advertisementRepository = dataSource.getRepository(Advertisement);

      // 创建租户2的广告
      const tenant2Advertisement = advertisementRepository.create({
        title: '租户2私有广告',
        typeId: testAdvertisementType.id,
        code: 'tenant2_private',
        url: 'https://example.com',
        sort: 1,
        status: 1,
        actionType: 1,
        createdBy: testUser.id,
        tenantId: 2
      });
      await advertisementRepository.save(tenant2Advertisement);

      // 租户1尝试访问租户2的广告
      const response = await client[':id'].$get({
        param: { id: tenant2Advertisement.id }
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      // 应该返回404，因为租户1不能访问租户2的数据
      expect(response.status).toBe(404);
    });
  });
});