import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { testClient } from 'hono/testing';
import { IntegrationTestDatabase, setupIntegrationDatabaseHooksWithEntities } from '@d8d/shared-test-util';
import { JWTUtil } from '@d8d/shared-utils';
import { z } from '@hono/zod-openapi';
import { createCrudRoutes } from '../../src/routes/generic-crud.routes';
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';

// 测试实体类 - 包含decimal和bigint字段
@Entity()
class TestNumberEntity {
  @PrimaryGeneratedColumn()
  id!: number;

  @Column('varchar')
  name!: string;

  @Column({ type: 'decimal', precision: 10, scale: 2, default: 0.00 })
  price!: number;

  @Column({ type: 'bigint', unsigned: true, default: 0 })
  quantity!: number;

  @Column({ type: 'decimal', precision: 15, scale: 4, nullable: true })
  discount?: number;

  @Column('int')
  userId!: number;
}

// 定义测试实体的Schema
const createTestSchema = z.object({
  name: z.string().min(1, '名称不能为空'),
  price: z.coerce.number().positive('价格必须为正数'),
  quantity: z.coerce.number().int().min(0, '数量必须为非负整数'),
  discount: z.coerce.number().min(0).max(1).optional(),
  userId: z.coerce.number().optional()
});

const getTestSchema = z.object({
  id: z.coerce.number(),
  name: z.string(),
  price: z.coerce.number(),
  quantity: z.coerce.number(),
  discount: z.coerce.number().nullable().optional(),
  userId: z.coerce.number()
});

const listTestSchema = z.object({
  id: z.coerce.number(),
  name: z.string(),
  price: z.coerce.number(),
  quantity: z.coerce.number(),
  discount: z.coerce.number().nullable().optional(),
  userId: z.coerce.number()
});

const updateTestSchema = z.object({
  name: z.string().min(1, '名称不能为空').optional(),
  price: z.coerce.number().positive('价格必须为正数').optional(),
  quantity: z.coerce.number().int().min(0, '数量必须为非负整数').optional(),
  discount: z.coerce.number().min(0).max(1).optional()
});

// 设置集成测试钩子
setupIntegrationDatabaseHooksWithEntities([TestNumberEntity])

describe('共享CRUD Schema类型转换集成测试', () => {

  let client: any;
  let testToken: string;
  const testUser = { id: 1, username: 'testuser' };

  beforeEach(async () => {
    // 创建测试路由
    const app = createCrudRoutes({
      entity: TestNumberEntity,
      createSchema: createTestSchema,
      updateSchema: updateTestSchema,
      getSchema: getTestSchema,
      listSchema: listTestSchema,
      dataPermission: {
        enabled: true,
        userIdField: 'userId'
      }
    });

    client = testClient(app);
    testToken = JWTUtil.generateToken(testUser);
  });

  // setupIntegrationDatabaseHooksWithEntities 已经自动处理了数据库清理

  describe('创建操作 - 数字类型转换', () => {
    it('应该正确处理decimal和bigint字段的创建和返回', async () => {
      // 使用 z.coerce.number() 后，schema验证应该成功
      const createData = {
        name: '测试商品',
        price: 99.99,
        quantity: 1000,
        discount: 0.1,
        userId: testUser.id
      };

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

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

      const result = await response.json();
      console.debug('创建商品返回结果:', result);

      // 验证返回的数据类型
      expect(typeof result.price).toBe('number');
      expect(result.price).toBe(99.99);
      expect(typeof result.quantity).toBe('number');
      expect(result.quantity).toBe(1000);
      expect(typeof result.discount).toBe('number');
      expect(result.discount).toBe(0.1);
    });

    it('应该处理没有discount字段的创建', async () => {
      const createData = {
        name: '测试商品无折扣',
        price: 50.00,
        quantity: 500,
        userId: testUser.id
      };

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

      expect(response.status).toBe(201);

      const result = await response.json();

      // 验证返回的数据类型
      expect(typeof result.price).toBe('number');
      expect(result.price).toBe(50.00);
      expect(typeof result.quantity).toBe('number');
      expect(result.quantity).toBe(500);
      expect(result.discount).toBeNull(); // 没有discount字段应该返回null
    });
  });

  describe('更新操作 - 数字类型转换', () => {
    let createdId: number;

    beforeEach(async () => {
      // 先创建一个测试数据
      const createData = {
        name: '原始商品',
        price: 100.00,
        quantity: 100,
        discount: 0.2,
        userId: testUser.id
      };

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

      const result = await response.json();
      createdId = result.id;
    });

    it('应该正确处理decimal和bigint字段的更新和返回', async () => {
      const updateData = {
        name: '更新后的商品',
        price: 88.88,
        quantity: 888,
        discount: 0.15
      };

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

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

      const result = await response.json();
      console.debug('更新商品返回结果:', result);

      // 验证返回的数据类型
      expect(result.id).toBe(createdId);
      expect(result.name).toBe(updateData.name);

      // 关键验证：更新后的price字段应该是数字类型
      expect(typeof result.price).toBe('number');
      expect(result.price).toBe(88.88);

      // 关键验证：更新后的quantity字段应该是数字类型
      expect(typeof result.quantity).toBe('number');
      expect(result.quantity).toBe(888);

      // 关键验证：更新后的discount字段应该是数字类型
      expect(typeof result.discount).toBe('number');
      expect(result.discount).toBe(0.15);
    });

    it('应该处理部分字段的更新', async () => {
      const updateData = {
        price: 66.66
      };

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

      expect(response.status).toBe(200);

      const result = await response.json();

      // 验证只有price字段被更新，其他字段保持不变
      expect(result.name).toBe('原始商品');
      expect(typeof result.price).toBe('number');
      expect(result.price).toBe(66.66);
      expect(typeof result.quantity).toBe('number');
      expect(result.quantity).toBe(100); // 原始值
      expect(typeof result.discount).toBe('number');
      expect(result.discount).toBe(0.2); // 原始值
    });
  });

  describe('获取操作 - 数字类型转换', () => {
    let createdId: number;

    beforeEach(async () => {
      // 先创建一个测试数据
      const createData = {
        name: '查询测试商品',
        price: 123.45,
        quantity: 999,
        discount: 0.05,
        userId: testUser.id
      };

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

      const result = await response.json();
      createdId = result.id;
    });

    it('应该正确处理decimal和bigint字段的查询返回', async () => {
      const response = await client['/:id'].$get({
        param: { id: createdId }
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

      console.debug('获取商品响应状态:', response.status);
      expect(response.status).toBe(200);

      const result = await response.json();
      console.debug('获取商品返回结果:', result);

      // 验证返回的数据类型
      expect(result.id).toBe(createdId);
      expect(result.name).toBe('查询测试商品');

      // 关键验证：price字段应该是数字类型
      expect(typeof result.price).toBe('number');
      expect(result.price).toBe(123.45);

      // 关键验证：quantity字段应该是数字类型
      expect(typeof result.quantity).toBe('number');
      expect(result.quantity).toBe(999);

      // 关键验证：discount字段应该是数字类型
      expect(typeof result.discount).toBe('number');
      expect(result.discount).toBe(0.05);
    });
  });

  describe('列表查询 - 数字类型转换', () => {
    beforeEach(async () => {
      // 创建多个测试数据
      const testData = [
        { name: '商品1', price: 10.50, quantity: 100, discount: 0.1, userId: testUser.id },
        { name: '商品2', price: 20.75, quantity: 200, discount: 0.2, userId: testUser.id },
        { name: '商品3', price: 30.99, quantity: 300, userId: testUser.id } // 没有discount
      ];

      for (const data of testData) {
        await client['/'].$post({
          json: data
        }, {
          headers: {
            'Authorization': `Bearer ${testToken}`
          }
        });
      }
    });

    it('应该正确处理列表查询中的数字类型转换', async () => {
      const response = await client['/'].$get({
        query: { page: 1, pageSize: 10 }
      }, {
        headers: {
          'Authorization': `Bearer ${testToken}`
        }
      });

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

      const result = await response.json();
      console.debug('列表查询返回结果:', result);

      expect(result).toHaveProperty('data');
      expect(result).toHaveProperty('pagination');
      expect(Array.isArray(result.data)).toBe(true);

      // 验证每个商品的数字字段类型
      result.data.forEach((item: any) => {
        expect(typeof item.price).toBe('number');
        expect(typeof item.quantity).toBe('number');

        // discount字段可能为数字或null
        if (item.discount !== null) {
          expect(typeof item.discount).toBe('number');
        }
      });

      // 验证具体数值
      const item1 = result.data.find((item: any) => item.name === '商品1');
      expect(item1).toBeDefined();
      expect(item1.price).toBe(10.50);
      expect(item1.quantity).toBe(100);
      expect(item1.discount).toBe(0.1);

      const item3 = result.data.find((item: any) => item.name === '商品3');
      expect(item3).toBeDefined();
      expect(item3.discount).toBeNull();
    });
  });
});