import { ConflictException, NotFoundException } from '@nestjs/common';
import { jest } from '@jest/globals';
import { UsersService } from './users.service.js';
import type { PrismaService } from '../prisma.service.js';

describe('UsersService.bindOpenIdForMiniAppLogin', () => {
  function createService() {
    const prisma = {
      user: {
        findUnique: jest.fn(),
        update: jest.fn(),
      },
    } as unknown as PrismaService;

    return {
      prisma,
      service: new UsersService(prisma),
    };
  }

  it('允许同一个 openId 绑定多个院内账号', async () => {
    const { prisma, service } = createService();
    const sharedOpenId = 'shared-openid';

    (prisma.user.findUnique as jest.Mock)
      .mockResolvedValueOnce({ id: 1, openId: null })
      .mockResolvedValueOnce({ id: 2, openId: null });
    (prisma.user.update as jest.Mock).mockResolvedValue(undefined);

    await service.bindOpenIdForMiniAppLogin(1, sharedOpenId);
    await service.bindOpenIdForMiniAppLogin(2, sharedOpenId);

    expect(prisma.user.update).toHaveBeenNthCalledWith(1, {
      where: { id: 1 },
      data: { openId: sharedOpenId },
    });
    expect(prisma.user.update).toHaveBeenNthCalledWith(2, {
      where: { id: 2 },
      data: { openId: sharedOpenId },
    });
  });

  it('拒绝用新的微信账号覆盖已绑定院内账号', async () => {
    const { prisma, service } = createService();

    (prisma.user.findUnique as jest.Mock).mockResolvedValue({
      id: 1,
      openId: 'bound-openid',
    });

    await expect(
      service.bindOpenIdForMiniAppLogin(1, 'other-openid'),
    ).rejects.toThrow(new ConflictException('当前院内账号已绑定其他微信账号'));
    expect(prisma.user.update).not.toHaveBeenCalled();
  });

  it('目标院内账号不存在时返回 404', async () => {
    const { prisma, service } = createService();

    (prisma.user.findUnique as jest.Mock).mockResolvedValue(null);

    await expect(
      service.bindOpenIdForMiniAppLogin(999, 'shared-openid'),
    ).rejects.toThrow(new NotFoundException('用户不存在'));
  });
});
