import { Test } from '@nestjs/testing';
import { Prisma } from '@prisma/client';
import { SyncService } from './sync.service';
import { SdsClientService } from './sds-client.service';
import { FamilyRecomputeService } from '../product-families/family-recompute.service';
import { PrismaService } from '../prisma/prisma.service';

/**
 * 同步钩子集成测试：upsertOriginGood 的解析列写入、新链接自动挂族、
 * persistProductDetail 后的族重算入队。
 */
describe('SyncService family hooks', () => {
  let service: SyncService;
  let prisma: PrismaService;
  let recompute: FamilyRecomputeService;
  const stamp = Date.now();
  const createdOriginGoodIds: bigint[] = [];
  const createdFamilyIds: bigint[] = [];

  const sdsProduct = (id: string, name: string) =>
    ({ id, name, pic: 'https://example.com/pic.jpg' }) as any;

  beforeAll(async () => {
    const moduleRef = await Test.createTestingModule({
      providers: [
        SyncService,
        {
          provide: SdsClientService,
          useValue: {},
        },
        FamilyRecomputeService,
        PrismaService,
      ],
    }).compile();
    service = moduleRef.get(SyncService);
    prisma = moduleRef.get(PrismaService);
    recompute = moduleRef.get(FamilyRecomputeService);
    await prisma.onModuleInit();
  });

  afterAll(async () => {
    await prisma.originGood.deleteMany({ where: { id: { in: createdOriginGoodIds } } });
    await prisma.productFamily.deleteMany({ where: { id: { in: createdFamilyIds } } });
    await prisma.$disconnect();
  });

  it('upsertOriginGood：写入四个解析列（create 与 update 全量覆盖）', async () => {
    const sdsId = `hook-${stamp}-parse`;
    const result1 = await (service as any).upsertOriginGood(
      sdsProduct(sdsId, '美国（包邮）240g涤纶休闲短裤-DG206-单面印花-美西洛杉矶一仓'),
      `cat-${stamp}-parse`,
    );
    expect(result1).toBe('inserted');
    const og = await prisma.originGood.findUniqueOrThrow({ where: { sdsGoodId: sdsId } });
    createdOriginGoodIds.push(og.id);
    expect(og.skuCode).toBe('DG206');
    expect(og.logisticsLabel).toBe('包邮');
    expect(og.craftLabel).toBe('单面印花');
    expect(og.warehouseLabel).toBe('美西洛杉矶一仓');

    // 更新为不带仓库的名称 → 解析列全量覆盖（warehouseLabel 置空）
    await (service as any).upsertOriginGood(
      sdsProduct(sdsId, '美国（不包邮）240g涤纶休闲短裤-DG206-单面印花'),
      `cat-${stamp}-parse`,
    );
    const og2 = await prisma.originGood.findUniqueOrThrow({ where: { sdsGoodId: sdsId } });
    expect(og2.logisticsLabel).toBe('不包邮');
    expect(og2.warehouseLabel).toBeNull();
  });

  it('新链接自动挂族：按 SDS 分类唯一命中族则挂载并触发重算', async () => {
    const sdsCat = `cat-hook-${stamp}`;
    const cat = await prisma.category.create({
      data: { categoryName: `挂族测试分类-${stamp}`, sdsCategoryId: sdsCat },
    });
    const seed = await prisma.originGood.create({
      data: {
        sdsGoodId: `hook-${stamp}-seed`,
        goodName: `自动挂${stamp}（包邮）卫衣-ZZA${stamp}-单面印花`,
        sdsCategoryId: sdsCat,
        craftLabel: '单面印花',
        logisticsLabel: '包邮',
      },
    });
    createdOriginGoodIds.push(seed.id);
    await prisma.originGoodVariant.create({
      data: {
        originGoodId: seed.id,
        sdsVariantId: 'seed-v1',
        sku: 'SEED-S',
        sizeId: 'size_S',
        sizeName: 'S',
        colorId: 'color_blk',
        colorName: '黑色',
        price: new Prisma.Decimal(25),
      },
    });
    const family = await prisma.productFamily.create({
      data: {
        familyName: `自动挂族-${stamp}`,
        primaryOriginGoodId: seed.id,
      },
    });
    createdFamilyIds.push(family.id);
    await prisma.originGood.update({
      where: { id: seed.id },
      data: { familyId: family.id },
    });
    await recompute.recomputeFamily(family.id);
    const before = await prisma.productFamily.findUniqueOrThrow({ where: { id: family.id } });
    expect((before.priceMatrix as any).rows).toHaveLength(1);

    // 同分类新链接（不同工艺）→ 自动挂进唯一族
    const newSdsId = `hook-${stamp}-new`;
    await (service as any).upsertOriginGood(
      sdsProduct(newSdsId, `自动挂${stamp}（不包邮）卫衣-ZZA${stamp}-双面印花-某仓`),
      sdsCat,
    );
    const newOg = await prisma.originGood.findUniqueOrThrow({ where: { sdsGoodId: newSdsId } });
    createdOriginGoodIds.push(newOg.id);
    expect(newOg.familyId).toBe(family.id);

    // 入队的重算已执行（等待异步完成）
    await new Promise((r) => setTimeout(r, 200));
    await prisma.category.delete({ where: { id: cat.id } }).catch(() => undefined);
  });

  it('多族命中时不确定归属 → 不挂载', async () => {
    // 两个族各含一个同分类成员 → 新链接分类命中两个族，归属不明，留给管理员
    const sdsCat = `cat-multi-${stamp}`;
    const mk = async (suffix: string) => {
      const og = await prisma.originGood.create({
        data: {
          sdsGoodId: `hook-${stamp}-multi-${suffix}`,
          goodName: `${suffix}（包邮）卫衣-ZZB${stamp}-单面印花`,
          sdsCategoryId: sdsCat,
          craftLabel: '单面印花',
          logisticsLabel: '包邮',
        },
      });
      createdOriginGoodIds.push(og.id);
      const family = await prisma.productFamily.create({
        data: { familyName: `多族${suffix}-${stamp}`, primaryOriginGoodId: og.id },
      });
      createdFamilyIds.push(family.id);
      await prisma.originGood.update({ where: { id: og.id }, data: { familyId: family.id } });
      return og;
    };
    await mk('x');
    await mk('y');

    const sdsId = `hook-${stamp}-multi-new`;
    await (service as any).upsertOriginGood(
      sdsProduct(sdsId, `新（包邮）卫衣-ZZB${stamp}-单面印花-新仓`),
      sdsCat,
    );
    const og = await prisma.originGood.findUniqueOrThrow({ where: { sdsGoodId: sdsId } });
    createdOriginGoodIds.push(og.id);
    expect(og.familyId).toBeNull(); // 两个候选族 → 留给管理员
  });

  it('maybeEnqueueFamilyRecompute：有族入队、无族跳过', async () => {
    const enqueueSpy = jest.spyOn(recompute, 'enqueue').mockImplementation(() => undefined);

    const og = await prisma.originGood.create({
      data: { sdsGoodId: `hook-${stamp}-noattach`, goodName: `不成组名称-${stamp}` },
    });
    createdOriginGoodIds.push(og.id);
    await (service as any).maybeEnqueueFamilyRecompute(og.id);
    expect(enqueueSpy).not.toHaveBeenCalled();

    const family = await prisma.productFamily.create({
      data: { familyName: `入队族-${stamp}` },
    });
    createdFamilyIds.push(family.id);
    await prisma.originGood.update({ where: { id: og.id }, data: { familyId: family.id } });
    await (service as any).maybeEnqueueFamilyRecompute(og.id);
    expect(enqueueSpy).toHaveBeenCalledWith(family.id);

    enqueueSpy.mockRestore();
  });
});
