import { describe, it, expect, beforeEach, vi } from 'vitest';
import { testClient } from 'hono/testing';
import {
  IntegrationTestDatabase,
  setupIntegrationDatabaseHooksWithEntities
} from '@d8d/shared-test-util';
import {
  IntegrationTestAssertions
} from '../utils/integration-test-utils';
import fileRoutes from '../../src/routes/index';
import { File } from '../../src/entities';
import { UserEntity, Role } from '@d8d/core-module/user-module';
import { TestDataFactory } from '../utils/integration-test-db';
import { AuthService } from '@d8d/core-module/auth-module';
import { UserService } from '@d8d/core-module/user-module';
import { MinioService } from '../../src/services/minio.service';

// Mock MinIO service to avoid real connections in tests
vi.mock('../../src/services/minio.service', () => {
  const MockMinioService = vi.fn(() => ({
    bucketName: 'test-bucket',
    ensureBucketExists: vi.fn().mockResolvedValue(true),
    objectExists: vi.fn().mockResolvedValue(false), // Assume files don't exist in MinIO for tests
    deleteObject: vi.fn().mockResolvedValue(undefined),
    generateUploadPolicy: vi.fn().mockResolvedValue({
      'x-amz-algorithm': 'AWS4-HMAC-SHA256',
      'x-amz-credential': 'test-credential',
      'x-amz-date': '20230101T000000Z',
      policy: 'test-policy',
      'x-amz-signature': 'test-signature',
      host: 'http://localhost:9000',
      key: 'test-key',
      bucket: 'test-bucket'
    }),
    getPresignedFileUrl: vi.fn().mockResolvedValue('http://localhost:9000/test-bucket/test-file'),
    getPresignedFileDownloadUrl: vi.fn().mockResolvedValue('http://localhost:9000/test-bucket/test-file?download=true'),
    createMultipartUpload: vi.fn().mockResolvedValue('test-upload-id'),
    generateMultipartUploadUrls: vi.fn().mockResolvedValue(['http://localhost:9000/part1', 'http://localhost:9000/part2']),
    completeMultipartUpload: vi.fn().mockResolvedValue({ size: 1024 }),
    createObject: vi.fn().mockResolvedValue('http://localhost:9000/test-bucket/test-file'),
    getFileUrl: vi.fn().mockReturnValue('http://localhost:9000/test-bucket/test-file')
  }));
  return { MinioService: MockMinioService };
});

// 设置集成测试钩子
setupIntegrationDatabaseHooksWithEntities([File, UserEntity, Role])

describe('文件路由API集成测试 (使用hono/testing)', () => {
  let client: ReturnType<typeof testClient<typeof fileRoutes>>;
  let authService: AuthService;
  let userService: UserService;
  let testToken: string;
  let testUser: any;

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

    // 获取数据源
    const dataSource = await IntegrationTestDatabase.getDataSource();
    if (!dataSource) throw new Error('Database not initialized');

    // 初始化服务
    userService = new UserService(dataSource);
    authService = new AuthService(userService);

    // 创建测试用户并生成token
    testUser = await TestDataFactory.createTestUser(dataSource, {
      username: 'testuser_file',
      password: 'TestPassword123!',
      email: 'testuser_file@example.com'
    });

    // 生成测试用户的token
    testToken = authService.generateToken(testUser);
  });

  describe('文件创建路由测试', () => {
    it('应该拒绝无认证令牌的文件创建请求', async () => {
      const fileData = {
        name: 'test.txt',
        type: 'text/plain',
        size: 1024,
        path: '/uploads/test.txt',
        description: 'Test file'
      };

      const response = await client['upload-policy'].$post({
        json: fileData
      });

      // 应该返回401状态码，因为缺少认证
      expect(response.status).toBe(401);
      if (response.status === 401) {
        const responseData = await response.json();
        expect(responseData.message).toContain('Authorization header missing');
      }
    });

    it('应该拒绝无效认证令牌的文件创建请求', async () => {
      const fileData = {
        name: 'test.txt',
        type: 'text/plain',
        size: 1024,
        path: '/uploads/test.txt',
        description: 'Test file'
      };

      const response = await client['upload-policy'].$post({
        json: fileData
      }, {
        headers: {
          'Authorization': 'Bearer invalid.token.here'
        }
      });

      // 应该返回401状态码，因为令牌无效
      expect(response.status).toBe(401);
      if (response.status === 401) {
        const responseData = await response.json();
        expect(responseData.message).toContain('Invalid token');
      }
    });

    it('应该成功创建文件上传策略（使用有效认证令牌）', async () => {
      const fileData = {
        name: 'test.txt',
        type: 'text/plain',
        size: 1024,
        path: '/uploads/test.txt',
        description: 'Test file'
      };

      const response = await client['upload-policy'].$post({
        json: fileData
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      // 断言响应
      if (response.status !== 200) {
        const errorData = await response.json();
        console.debug('File creation error:', JSON.stringify(errorData, null, 2));
      }
      expect(response.status).toBe(200);
      if (response.status === 200) {
        const responseData = await response.json();
        expect(responseData).toHaveProperty('file');
        expect(responseData).toHaveProperty('uploadPolicy');
        expect(responseData.file.name).toBe(fileData.name);
        expect(responseData.file.type).toBe(fileData.type);
        expect(responseData.file.size).toBe(fileData.size);
        expect(responseData.file.uploadUserId).toBe(testUser.id);

        // 断言数据库中存在文件记录
        const dataSource = await IntegrationTestDatabase.getDataSource();
        if (!dataSource) throw new Error('Database not initialized');

        const fileRepository = dataSource.getRepository(File);
        const savedFile = await fileRepository.findOne({
          where: { name: fileData.name }
        });
        expect(savedFile).toBeTruthy();
        expect(savedFile?.uploadUserId).toBe(testUser.id);
      }
    });

    it('应该拒绝创建无效文件数据的请求', async () => {
      const invalidFileData = {
        name: '', // 空文件名
        type: 'text/plain',
        path: 'test/path.txt'
      };

      const response = await client['upload-policy'].$post({
        json: invalidFileData
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      // 应该返回验证错误
      expect([400, 500]).toContain(response.status);
    });
  });

  describe('文件读取路由测试', () => {
    it('应该成功获取文件列表', async () => {
      const dataSource = await IntegrationTestDatabase.getDataSource();
      if (!dataSource) throw new Error('Database not initialized');

      // 创建几个测试文件
      await TestDataFactory.createTestFile(dataSource, {
        name: 'file1.txt',
        uploadUserId: testUser.id
      });
      await TestDataFactory.createTestFile(dataSource, {
        name: 'file2.txt',
        uploadUserId: testUser.id
      });

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


      expect(response.status).toBe(200);
      if (response.status === 200) {
        const responseData = await response.json();
        expect(Array.isArray(responseData.data)).toBe(true);
        expect(responseData.data.length).toBeGreaterThanOrEqual(2);
      }
    });

    it('应该成功获取单个文件详情', async () => {
      const dataSource = await IntegrationTestDatabase.getDataSource();
      if (!dataSource) throw new Error('Database not initialized');

      const testFile = await TestDataFactory.createTestFile(dataSource, {
        name: 'testfile_detail',
        uploadUserId: testUser.id
      });

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

      expect(response.status).toBe(200);
      if (response.status === 200) {
        const responseData = await response.json();
        expect(responseData.id).toBe(testFile.id);
        expect(responseData.name).toBe(testFile.name);
        expect(responseData.type).toBe(testFile.type);
      }
    });

    it('应该返回404当文件不存在时', async () => {
      const response = await client[':id'].$get({
        param: { id: 999999 }
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      expect(response.status).toBe(404);
      if (response.status === 404) {
        const responseData = await response.json();
        expect(responseData.message).toContain('资源不存在');
      }
    });
  });

  describe('文件URL生成路由测试', () => {
    it('应该成功生成文件访问URL', async () => {
      const dataSource = await IntegrationTestDatabase.getDataSource();
      if (!dataSource) throw new Error('Database not initialized');

      const testFile = await TestDataFactory.createTestFile(dataSource, {
        name: 'testfile_url',
        uploadUserId: testUser.id
      });

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

      expect(response.status).toBe(200);
      if (response.status === 200) {
        const responseData = await response.json();
        expect(responseData).toHaveProperty('url');
        expect(typeof responseData.url).toBe('string');
        expect(responseData.url.length).toBeGreaterThan(0);
      }
    });

    it('应该返回404当为不存在的文件生成URL时', async () => {
      const response = await client[':id']['url'].$get({
        param: { id: 999999 }
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      expect(response.status).toBe(404);
      if (response.status === 404) {
        const responseData = await response.json();
        expect(responseData.message).toContain('文件不存在');
      }
    });
  });

  describe('文件下载路由测试', () => {
    it('应该成功生成文件下载URL', async () => {
      const dataSource = await IntegrationTestDatabase.getDataSource();
      if (!dataSource) throw new Error('Database not initialized');

      const testFile = await TestDataFactory.createTestFile(dataSource, {
        name: 'testfile_download.txt',
        uploadUserId: testUser.id
      });

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

      expect(response.status).toBe(200);
      if (response.status === 200) {
        const responseData = await response.json();
        expect(responseData).toHaveProperty('url');
        expect(responseData).toHaveProperty('filename');
        expect(typeof responseData.url).toBe('string');
        expect(responseData.filename).toBe(testFile.name);
      }
    });

    it('应该返回404当为不存在的文件生成下载URL时', async () => {
      const response = await client[':id']['download'].$get({
        param: { id: 999999 }
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      expect(response.status).toBe(404);
      if (response.status === 404) {
        const responseData = await response.json();
        expect(responseData.message).toContain('文件不存在');
      }
    });
  });

  describe('文件删除路由测试', () => {
    it('应该拒绝无认证令牌的文件删除请求', async () => {
      const dataSource = await IntegrationTestDatabase.getDataSource();
      if (!dataSource) throw new Error('Database not initialized');

      const testFile = await TestDataFactory.createTestFile(dataSource, {
        name: 'testfile_delete_no_auth',
        uploadUserId: testUser.id
      });

      const response = await client[':id'].$delete({
        param: { id: testFile.id }
      });

      // 应该返回401状态码，因为缺少认证
      expect(response.status).toBe(401);
      if (response.status === 401) {
        const responseData = await response.json();
        expect(responseData.message).toContain('Authorization header missing');
      }
    });

    it('应该成功删除文件（使用有效认证令牌）', async () => {
      const dataSource = await IntegrationTestDatabase.getDataSource();
      if (!dataSource) throw new Error('Database not initialized');

      const testFile = await TestDataFactory.createTestFile(dataSource, {
        name: 'testfile_delete',
        uploadUserId: testUser.id
      });

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

      IntegrationTestAssertions.expectStatus(response, 200);

      // 验证文件已从数据库中删除
      const fileRepository = dataSource.getRepository(File);
      const deletedFile = await fileRepository.findOne({
        where: { id: testFile.id }
      });
      expect(deletedFile).toBeNull();

      // 验证再次获取文件返回404
      const getResponse = await client[':id'].$get({
        param: { id: testFile.id }
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });
      IntegrationTestAssertions.expectStatus(getResponse, 404);
    });

    it('应该返回404当删除不存在的文件时', async () => {
      const response = await client[':id'].$delete({
        param: { id: 999999 }
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      IntegrationTestAssertions.expectStatus(response, 404);
      if (response.status === 404) {
        const responseData = await response.json();
        expect(responseData.message).toContain('文件不存在');
      }
    });
  });

  describe('文件搜索路由测试', () => {
    it('应该能够按文件名搜索文件', async () => {
      const dataSource = await IntegrationTestDatabase.getDataSource();
      if (!dataSource) throw new Error('Database not initialized');

      await TestDataFactory.createTestFile(dataSource, {
        name: 'search_file_1.txt',
        uploadUserId: testUser.id
      });
      await TestDataFactory.createTestFile(dataSource, {
        name: 'search_file_2.txt',
        uploadUserId: testUser.id
      });
      await TestDataFactory.createTestFile(dataSource, {
        name: 'other_file.txt',
        uploadUserId: testUser.id
      });

      const response = await client.index.$get({
        query: { keyword: 'search_file' }
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      IntegrationTestAssertions.expectStatus(response, 200);
      if (response.status === 200) {
        const responseData = await response.json();
        expect(Array.isArray(responseData.data)).toBe(true);
        expect(responseData.data.length).toBe(2);

        // 验证搜索结果包含正确的文件
        const filenames = responseData.data.map((file: any) => file.name);
        expect(filenames).toContain('search_file_1.txt');
        expect(filenames).toContain('search_file_2.txt');
        expect(filenames).not.toContain('other_file.txt');
      }
    });

    it('应该能够按文件类型搜索文件', async () => {
      const dataSource = await IntegrationTestDatabase.getDataSource();
      if (!dataSource) throw new Error('Database not initialized');

      await TestDataFactory.createTestFile(dataSource, {
        name: 'image1.jpg',
        type: 'image/jpeg',
        uploadUserId: testUser.id
      });
      await TestDataFactory.createTestFile(dataSource, {
        name: 'image2.png',
        type: 'image/png',
        uploadUserId: testUser.id
      });

      const response = await client.index.$get({
        query: { keyword: 'image' }
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      IntegrationTestAssertions.expectStatus(response, 200);
      if (response.status === 200) {
        const responseData = await response.json();
        expect(responseData.data.length).toBe(2);

        const types = responseData.data.map((file: any) => file.type);
        expect(types).toContain('image/jpeg');
        expect(types).toContain('image/png');
      }
    });
  });

  describe('性能测试', () => {
    it('文件列表查询响应时间应小于200ms', async () => {
      const dataSource = await IntegrationTestDatabase.getDataSource();
      if (!dataSource) throw new Error('Database not initialized');

      // 创建一些测试数据
      for (let i = 0; i < 10; i++) {
        await TestDataFactory.createTestFile(dataSource, {
          name: `perf_file_${i}.txt`,
          uploadUserId: testUser.id
        });
      }

      const startTime = Date.now();
      const response = await client.index.$get({
        query: {}
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });
      const endTime = Date.now();
      const responseTime = endTime - startTime;

      IntegrationTestAssertions.expectStatus(response, 200);
      expect(responseTime).toBeLessThan(200); // 响应时间应小于200ms
    });
  });

  describe('认证令牌测试', () => {
    it('应该拒绝过期令牌的文件请求', async () => {
      // 创建立即过期的令牌
      const expiredToken = authService.generateToken(testUser, '1ms');

      // 等待令牌过期
      await new Promise(resolve => setTimeout(resolve, 10));

      const response = await client['upload-policy'].$post({
        json: {
          name: 'test_expired_token.txt',
          type: 'text/plain',
          size: 1024,
          path: 'test/expired_token.txt'
        }
      }, {
        headers: {
          'Authorization': `Bearer ${expiredToken}`
        }
      });

      // 应该返回401状态码，因为令牌过期
      expect(response.status).toBe(401);
      if (response.status === 401) {
        const responseData = await response.json();
        expect(responseData.message).toContain('Invalid token');
      }
    });

    it('应该拒绝格式错误的认证头', async () => {
      const response = await client['upload-policy'].$post({
        json: {
          name: 'test_bad_auth_header.txt',
          type: 'text/plain',
          size: 1024,
          path: 'test/bad_auth_header.txt'
        }
      }, {
        headers: {
          'Authorization': 'Basic invalid_format'
        }
      });

      // 应该返回401状态码，因为认证头格式错误
      expect(response.status).toBe(401);
      if (response.status === 401) {
        const responseData = await response.json();
        expect(responseData.message).toContain('Authorization header missing');
      }
    });
  });

});