import { describe, expect, it, vi, beforeEach } from 'vitest';
import { authChatCrud, authCollectionInChat } from '@/service/support/permission/auth/chat';
import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
import { MongoChatItem } from '@fastgpt/service/core/chat/chatItemSchema';
import { MongoChatItemResponse } from '@fastgpt/service/core/chat/chatItemResponseSchema';
import { AuthUserTypeEnum } from '@fastgpt/global/support/permission/constant';
import { ChatErrEnum } from '@fastgpt/global/common/error/code/chat';
import { DatasetErrEnum } from '@fastgpt/global/common/error/code/dataset';
import { authApp } from '@fastgpt/service/support/permission/app/auth';
import { authOutLink } from '@/service/support/permission/auth/outLink';
import { authTeamSpaceToken } from '@/service/support/permission/auth/team';
import { getFlatAppResponses } from '@/global/core/chat/utils';
import { AppPermission } from '@fastgpt/global/support/permission/app/controller';

vi.mock('@fastgpt/service/core/chat/chatSchema', () => ({
  MongoChat: {
    findOne: vi.fn()
  }
}));

vi.mock('@fastgpt/service/core/chat/chatItemSchema', () => ({
  MongoChatItem: {
    findOne: vi.fn(),
    find: vi.fn()
  }
}));

vi.mock('@fastgpt/service/core/chat/chatItemResponseSchema', () => ({
  MongoChatItemResponse: {
    find: vi.fn()
  }
}));

vi.mock('@fastgpt/service/support/permission/app/auth');
vi.mock('@/service/support/permission/auth/outLink');
vi.mock('@/service/support/permission/auth/team');
vi.mock('@/global/core/chat/utils');

describe('authChatCrud', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('validation', () => {
    it('should reject if appId is empty string', async () => {
      await expect(authChatCrud({ appId: '', req: {} as any, authToken: true })).rejects.toBe(
        ChatErrEnum.unAuthChat
      );
    });

    it('should reject if appId is undefined', async () => {
      await expect(
        authChatCrud({ appId: undefined as any, req: {} as any, authToken: true })
      ).rejects.toBe(ChatErrEnum.unAuthChat);
    });

    it('should reject if appId is null', async () => {
      await expect(
        authChatCrud({ appId: null as any, req: {} as any, authToken: true })
      ).rejects.toBe(ChatErrEnum.unAuthChat);
    });
  });

  describe('teamDomain authentication', () => {
    it('should auth with teamId and teamToken without chatId', async () => {
      vi.mocked(authTeamSpaceToken).mockResolvedValue({
        uid: 'user1',
        tmbId: 'tmb1'
      });

      const result = await authChatCrud({
        appId: 'app1',
        teamId: 'team1',
        teamToken: 'token1',
        req: {} as any,
        authToken: true
      });

      expect(result).toEqual({
        teamId: 'team1',
        tmbId: 'tmb1',
        uid: 'user1',
        responseDetail: true,
        showNodeStatus: true,
        showRawSource: true,
        authType: AuthUserTypeEnum.teamDomain
      });
    });

    it('should auth with teamId and teamToken with valid chatId', async () => {
      const mockChat = {
        appId: 'app1',
        outLinkUid: 'user1',
        teamId: 'team1'
      };

      vi.mocked(authTeamSpaceToken).mockResolvedValue({
        uid: 'user1',
        tmbId: 'tmb1'
      });
      vi.mocked(MongoChat.findOne).mockReturnValue({
        lean: () => Promise.resolve(mockChat)
      } as any);

      const result = await authChatCrud({
        appId: 'app1',
        chatId: 'chat1',
        teamId: 'team1',
        teamToken: 'token1',
        req: {} as any,
        authToken: true
      });

      expect(result).toEqual({
        teamId: 'team1',
        tmbId: 'tmb1',
        uid: 'user1',
        chat: mockChat,
        responseDetail: true,
        showNodeStatus: true,
        showRawSource: true,
        authType: AuthUserTypeEnum.teamDomain
      });
    });

    it('should handle missing chat for teamDomain auth', async () => {
      vi.mocked(authTeamSpaceToken).mockResolvedValue({
        uid: 'user1',
        tmbId: 'tmb1'
      });
      vi.mocked(MongoChat.findOne).mockReturnValue({
        lean: () => Promise.resolve(null)
      } as any);

      const result = await authChatCrud({
        appId: 'app1',
        chatId: 'chat1',
        teamId: 'team1',
        teamToken: 'token1',
        req: {} as any,
        authToken: true
      });

      expect(result).toEqual({
        teamId: 'team1',
        tmbId: 'tmb1',
        uid: 'user1',
        responseDetail: true,
        showNodeStatus: true,
        showRawSource: true,
        authType: AuthUserTypeEnum.teamDomain
      });
    });

    it('should reject if chat outLinkUid does not match user for teamDomain', async () => {
      const mockChat = {
        appId: 'app1',
        outLinkUid: 'different-user',
        teamId: 'team1'
      };

      vi.mocked(authTeamSpaceToken).mockResolvedValue({
        uid: 'user1',
        tmbId: 'tmb1'
      });
      vi.mocked(MongoChat.findOne).mockReturnValue({
        lean: () => Promise.resolve(mockChat)
      } as any);

      await expect(
        authChatCrud({
          appId: 'app1',
          chatId: 'chat1',
          teamId: 'team1',
          teamToken: 'token1',
          req: {} as any,
          authToken: true
        })
      ).rejects.toBe(ChatErrEnum.unAuthChat);
    });
  });

  describe('outLink authentication', () => {
    it('should auth outLink without chatId', async () => {
      vi.mocked(authOutLink).mockResolvedValue({
        outLinkConfig: {
          teamId: 'team1',
          tmbId: 'tmb1',
          responseDetail: true,
          showNodeStatus: true,
          showRawSource: true
        },
        uid: 'user1',
        appId: 'app1'
      });

      const result = await authChatCrud({
        appId: 'app1',
        shareId: 'share1',
        outLinkUid: 'user1',
        req: {} as any,
        authToken: true
      });

      expect(result).toMatchObject({
        teamId: 'team1',
        tmbId: 'tmb1',
        uid: 'user1',
        responseDetail: true,
        showNodeStatus: true,
        showRawSource: true,
        authType: AuthUserTypeEnum.outLink
      });
    });

    it('should auth outLink with default showNodeStatus and showRawSource', async () => {
      vi.mocked(authOutLink).mockResolvedValue({
        outLinkConfig: {
          teamId: 'team1',
          tmbId: 'tmb1',
          responseDetail: false,
          shareId: 'share1',
          outLinkUid: 'user1'
        },
        uid: 'user1',
        appId: 'app1'
      });

      const result = await authChatCrud({
        appId: 'app1',
        shareId: 'share1',
        outLinkUid: 'user1',
        req: {} as any,
        authToken: true
      });

      expect(result).toMatchObject({
        teamId: 'team1',
        tmbId: 'tmb1',
        uid: 'user1',
        responseDetail: false,
        showNodeStatus: true, // default
        showRawSource: false, // default
        authType: AuthUserTypeEnum.outLink
      });
    });

    it('should auth outLink with chatId', async () => {
      const mockChat = {
        appId: 'app1',
        outLinkUid: 'user1'
      };

      vi.mocked(authOutLink).mockResolvedValue({
        outLinkConfig: {
          teamId: 'team1',
          tmbId: 'tmb1',
          responseDetail: true,
          showNodeStatus: true,
          showRawSource: true
        },
        uid: 'user1',
        appId: 'app1'
      });

      vi.mocked(MongoChat.findOne).mockReturnValue({
        lean: () => Promise.resolve(mockChat)
      } as any);

      const result = await authChatCrud({
        appId: 'app1',
        chatId: 'chat1',
        shareId: 'share1',
        outLinkUid: 'user1',
        req: {} as any,
        authToken: true
      });

      expect(result).toMatchObject({
        teamId: 'team1',
        tmbId: 'tmb1',
        uid: 'user1',
        chat: mockChat,
        responseDetail: true,
        showNodeStatus: true,
        showRawSource: true,
        authType: AuthUserTypeEnum.outLink
      });
    });

    it('should handle missing chat for outLink auth', async () => {
      vi.mocked(authOutLink).mockResolvedValue({
        outLinkConfig: {
          teamId: 'team1',
          tmbId: 'tmb1',
          responseDetail: true,
          showNodeStatus: false,
          showRawSource: true
        },
        uid: 'user1',
        appId: 'app1'
      });

      vi.mocked(MongoChat.findOne).mockReturnValue({
        lean: () => Promise.resolve(null)
      } as any);

      const result = await authChatCrud({
        appId: 'app1',
        chatId: 'chat1',
        shareId: 'share1',
        outLinkUid: 'user1',
        req: {} as any,
        authToken: true
      });

      expect(result).toEqual({
        teamId: 'team1',
        tmbId: 'tmb1',
        uid: 'user1',
        responseDetail: true,
        showNodeStatus: false,
        showRawSource: true,
        authType: AuthUserTypeEnum.outLink
      });
    });

    it('should reject if chat outLinkUid does not match for outLink auth', async () => {
      const mockChat = {
        appId: 'app1',
        outLinkUid: 'different-user'
      };

      vi.mocked(authOutLink).mockResolvedValue({
        outLinkConfig: {
          teamId: 'team1',
          tmbId: 'tmb1',
          responseDetail: true
        },
        uid: 'user1',
        appId: 'app1'
      });

      vi.mocked(MongoChat.findOne).mockReturnValue({
        lean: () => Promise.resolve(mockChat)
      } as any);

      await expect(
        authChatCrud({
          appId: 'app1',
          chatId: 'chat1',
          shareId: 'share1',
          outLinkUid: 'user1',
          req: {} as any,
          authToken: true
        })
      ).rejects.toBe(ChatErrEnum.unAuthChat);
    });

    it('should reject if outLink appId does not match', async () => {
      vi.mocked(authOutLink).mockResolvedValue({
        outLinkConfig: {
          teamId: 'team1',
          tmbId: 'tmb1'
        },
        uid: 'user1',
        appId: 'different-app'
      });

      await expect(
        authChatCrud({
          appId: 'app1',
          shareId: 'share1',
          outLinkUid: 'user1',
          req: {} as any,
          authToken: true
        })
      ).rejects.toBe(ChatErrEnum.unAuthChat);
    });

    it('should reject if shareId provided without outLinkUid', async () => {
      // Mock authApp to simulate what happens when req is provided but shareId/outLinkUid combo is incomplete
      vi.mocked(authApp).mockRejectedValue(new Error('Auth failed'));

      await expect(
        authChatCrud({
          appId: 'app1',
          shareId: 'share1',
          req: {} as any,
          authToken: true
        })
      ).rejects.toThrow();
    });

    it('should reject if outLinkUid provided without shareId', async () => {
      // Mock authApp to simulate what happens when req is provided but shareId/outLinkUid combo is incomplete
      vi.mocked(authApp).mockRejectedValue(new Error('Auth failed'));

      await expect(
        authChatCrud({
          appId: 'app1',
          outLinkUid: 'user1',
          req: {} as any,
          authToken: true
        })
      ).rejects.toThrow();
    });
  });

  describe('cookie authentication', () => {
    it('should auth with cookie without chatId', async () => {
      vi.mocked(authApp).mockResolvedValue({
        teamId: 'team1',
        tmbId: 'tmb1',
        permission: new AppPermission({
          isOwner: true
        }),
        authType: AuthUserTypeEnum.teamDomain
      } as any);

      const result = await authChatCrud({
        appId: 'app1',
        req: {} as any,
        authToken: true
      });

      expect(result).toEqual({
        teamId: 'team1',
        tmbId: 'tmb1',
        uid: 'tmb1',
        responseDetail: true,
        showNodeStatus: true,
        showRawSource: true,
        authType: AuthUserTypeEnum.teamDomain
      });
    });

    it('should auth with cookie and valid chatId for same team', async () => {
      const mockChat = {
        appId: 'app1',
        teamId: 'team1',
        tmbId: 'tmb1'
      };

      vi.mocked(authApp).mockResolvedValue({
        teamId: 'team1',
        tmbId: 'tmb1',
        permission: new AppPermission({
          isOwner: true
        }),
        authType: AuthUserTypeEnum.teamDomain
      } as any);

      vi.mocked(MongoChat.findOne).mockReturnValue({
        lean: () => Promise.resolve(mockChat)
      } as any);

      const result = await authChatCrud({
        appId: 'app1',
        chatId: 'chat1',
        req: {} as any,
        authToken: true
      });

      expect(result).toEqual({
        teamId: 'team1',
        tmbId: 'tmb1',
        uid: 'tmb1',
        chat: mockChat,
        responseDetail: true,
        showNodeStatus: true,
        showRawSource: true,
        authType: AuthUserTypeEnum.teamDomain
      });
    });

    it('should auth with readChatLogPer permission for different user chat', async () => {
      const mockChat = {
        appId: 'app1',
        teamId: 'team1',
        tmbId: 'different-tmb'
      };

      vi.mocked(authApp).mockResolvedValue({
        teamId: 'team1',
        tmbId: 'tmb1',
        permission: new AppPermission({
          isOwner: false,
          role: 8 // ReadChatLogRole value 0b1000
        }),
        authType: AuthUserTypeEnum.teamDomain
      } as any);

      vi.mocked(MongoChat.findOne).mockReturnValue({
        lean: () => Promise.resolve(mockChat)
      } as any);

      const result = await authChatCrud({
        appId: 'app1',
        chatId: 'chat1',
        req: {} as any,
        authToken: true
      });

      expect(result).toEqual({
        teamId: 'team1',
        tmbId: 'tmb1',
        uid: 'tmb1',
        chat: mockChat,
        responseDetail: true,
        showNodeStatus: true,
        showRawSource: true,
        authType: AuthUserTypeEnum.teamDomain
      });
    });

    it('should handle missing chat for cookie auth', async () => {
      vi.mocked(authApp).mockResolvedValue({
        teamId: 'team1',
        tmbId: 'tmb1',
        permission: new AppPermission({
          isOwner: true
        }),
        authType: AuthUserTypeEnum.teamDomain
      } as any);

      vi.mocked(MongoChat.findOne).mockReturnValue({
        lean: () => Promise.resolve(null)
      } as any);

      const result = await authChatCrud({
        appId: 'app1',
        chatId: 'chat1',
        req: {} as any,
        authToken: true
      });

      expect(result).toEqual({
        teamId: 'team1',
        tmbId: 'tmb1',
        uid: 'tmb1',
        responseDetail: true,
        showNodeStatus: true,
        showRawSource: true,
        authType: AuthUserTypeEnum.teamDomain
      });
    });

    it('should reject if chat belongs to different team', async () => {
      const mockChat = {
        appId: 'app1',
        teamId: 'different-team',
        tmbId: 'tmb1'
      };

      vi.mocked(authApp).mockResolvedValue({
        teamId: 'team1',
        tmbId: 'tmb1',
        permission: new AppPermission({
          isOwner: true
        }),
        authType: AuthUserTypeEnum.teamDomain
      } as any);

      vi.mocked(MongoChat.findOne).mockReturnValue({
        lean: () => Promise.resolve(mockChat)
      } as any);

      await expect(
        authChatCrud({
          appId: 'app1',
          chatId: 'chat1',
          req: {} as any,
          authToken: true
        })
      ).rejects.toBe(ChatErrEnum.unAuthChat);
    });

    it('should reject if user has no permission for different user chat', async () => {
      const mockChat = {
        appId: 'app1',
        teamId: 'team1',
        tmbId: 'different-tmb'
      };

      vi.mocked(authApp).mockResolvedValue({
        teamId: 'team1',
        tmbId: 'tmb1',
        permission: new AppPermission({
          isOwner: false,
          role: 0 // no role/permissions
        }),
        authType: AuthUserTypeEnum.teamDomain
      } as any);

      vi.mocked(MongoChat.findOne).mockReturnValue({
        lean: () => Promise.resolve(mockChat)
      } as any);

      await expect(
        authChatCrud({
          appId: 'app1',
          chatId: 'chat1',
          req: {} as any,
          authToken: true
        })
      ).rejects.toBe(ChatErrEnum.unAuthChat);
    });
  });
});

describe('authCollectionInChat', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('validation', () => {
    it('should reject if chat item not found', async () => {
      // Mock the find method to return empty array (no cite collection ids found)
      vi.mocked(MongoChatItem.find).mockReturnValue({
        sort: () => ({
          limit: () => ({
            lean: () => Promise.resolve([])
          })
        })
      } as any);

      vi.mocked(MongoChatItem.findOne).mockReturnValue({
        lean: () => Promise.resolve(null)
      } as any);

      await expect(
        authCollectionInChat({
          collectionIds: ['col1'],
          appId: 'app1',
          chatId: 'chat1',
          chatItemDataId: 'item1'
        })
      ).rejects.toBe(DatasetErrEnum.unAuthDatasetFile);
    });

    it('should reject with empty collectionIds array', async () => {
      // Mock the find method to return empty array (no cite collection ids found)
      vi.mocked(MongoChatItem.find).mockReturnValue({
        sort: () => ({
          limit: () => ({
            lean: () => Promise.resolve([])
          })
        })
      } as any);

      const mockChatItem = {
        time: new Date(),
        responseData: []
      };

      vi.mocked(MongoChatItem.findOne).mockReturnValue({
        lean: () => Promise.resolve(mockChatItem)
      } as any);
      vi.mocked(MongoChatItemResponse.find).mockReturnValue({
        lean: () => Promise.resolve([])
      } as any);
      vi.mocked(getFlatAppResponses).mockReturnValue([]);

      const result = await authCollectionInChat({
        collectionIds: [],
        appId: 'app1',
        chatId: 'chat1',
        chatItemDataId: 'item1'
      });

      expect(result).toEqual(undefined);
    });

    it('should handle missing appId, chatId, or chatItemDataId', async () => {
      await expect(
        authCollectionInChat({
          collectionIds: ['col1'],
          appId: '',
          chatId: 'chat1',
          chatItemDataId: 'item1'
        })
      ).rejects.toBe(DatasetErrEnum.unAuthDatasetFile);
    });
  });

  describe('response data handling', () => {
    it('should auth collection ids in chat item with existing responseData', async () => {
      // Mock the find method to return empty array (no cite collection ids found)
      vi.mocked(MongoChatItem.find).mockReturnValue({
        sort: () => ({
          limit: () => ({
            lean: () => Promise.resolve([])
          })
        })
      } as any);

      const mockChatItem = {
        time: new Date(),
        citeCollectionIds: ['col1', 'col2']
      };

      vi.mocked(MongoChatItem.findOne).mockReturnValue({
        lean: () => Promise.resolve(mockChatItem)
      } as any);
      vi.mocked(getFlatAppResponses).mockReturnValue([
        { quoteList: [{ collectionId: 'col1' }, { collectionId: 'col2' }] }
      ]);

      const result = await authCollectionInChat({
        collectionIds: ['col1', 'col2'],
        appId: 'app1',
        chatId: 'chat1',
        chatItemDataId: 'item1'
      });

      expect(result).toEqual(undefined);
    });

    it('should fetch responseData from MongoChatItemResponse when missing', async () => {
      const mockChatItem = {
        time: new Date(),
        citeCollectionIds: ['col1', 'col2']
      };
      const mockChatItemResponses = [
        { data: { quoteList: [{ collectionId: 'col1' }] } },
        { data: { quoteList: [{ collectionId: 'col2' }] } }
      ];

      vi.mocked(MongoChatItem.findOne).mockReturnValue({
        lean: () => Promise.resolve(mockChatItem)
      } as any);
      vi.mocked(MongoChatItemResponse.find).mockReturnValue({
        lean: () => Promise.resolve(mockChatItemResponses)
      } as any);
      vi.mocked(getFlatAppResponses).mockReturnValue([
        { quoteList: [{ collectionId: 'col1' }] },
        { quoteList: [{ collectionId: 'col2' }] }
      ]);

      const result = await authCollectionInChat({
        collectionIds: ['col1', 'col2'],
        appId: 'app1',
        chatId: 'chat1',
        chatItemDataId: 'item1'
      });

      expect(mockChatItem.responseData).toEqual([
        { quoteList: [{ collectionId: 'col1' }] },
        { quoteList: [{ collectionId: 'col2' }] }
      ]);
      expect(result).toEqual(undefined);
    });

    it('should handle empty responseData array', async () => {
      const mockChatItem = {
        time: new Date(),
        responseData: []
      };

      vi.mocked(MongoChatItem.findOne).mockReturnValue({
        lean: () => Promise.resolve(mockChatItem)
      } as any);
      vi.mocked(MongoChatItemResponse.find).mockReturnValue({
        lean: () => Promise.resolve([])
      } as any);
      vi.mocked(getFlatAppResponses).mockReturnValue([]);

      await expect(
        authCollectionInChat({
          collectionIds: ['col1'],
          appId: 'app1',
          chatId: 'chat1',
          chatItemDataId: 'item1'
        })
      ).rejects.toBe(DatasetErrEnum.unAuthDatasetFile);
    });

    it('should handle plugin, tool and loop details in response data', async () => {
      const mockChatItem = {
        time: new Date(),
        responseData: [
          {
            quoteList: [{ collectionId: 'col1' }],
            pluginDetail: [
              {
                quoteList: [{ collectionId: 'col2' }]
              }
            ],
            toolDetail: [
              {
                quoteList: [{ collectionId: 'col3' }]
              }
            ],
            loopDetail: [
              {
                quoteList: [{ collectionId: 'col4' }]
              }
            ]
          }
        ]
      };

      vi.mocked(MongoChatItem.findOne).mockReturnValue({
        lean: () => Promise.resolve(mockChatItem)
      } as any);
      vi.mocked(getFlatAppResponses).mockReturnValue([
        { quoteList: [{ collectionId: 'col1' }] },
        { quoteList: [{ collectionId: 'col2' }] },
        { quoteList: [{ collectionId: 'col3' }] },
        { quoteList: [{ collectionId: 'col4' }] }
      ]);

      const result = await authCollectionInChat({
        collectionIds: ['col1', 'col2', 'col3', 'col4'],
        appId: 'app1',
        chatId: 'chat1',
        chatItemDataId: 'item1'
      });

      expect(result).toEqual(undefined);
    });

    it('should reject if collection ids not found in quotes', async () => {
      const mockChatItem = {
        time: new Date(),
        responseData: [
          {
            quoteList: [{ collectionId: 'col1' }]
          }
        ]
      };

      vi.mocked(MongoChatItem.findOne).mockReturnValue({
        lean: () => Promise.resolve(mockChatItem)
      } as any);
      vi.mocked(getFlatAppResponses).mockReturnValue([{ quoteList: [{ collectionId: 'col1' }] }]);

      await expect(
        authCollectionInChat({
          collectionIds: ['col2'],
          appId: 'app1',
          chatId: 'chat1',
          chatItemDataId: 'item1'
        })
      ).rejects.toBe(DatasetErrEnum.unAuthDatasetFile);
    });

    it('should reject if only some collection ids are found', async () => {
      const mockChatItem = {
        time: new Date(),
        responseData: [
          {
            quoteList: [{ collectionId: 'col1' }, { collectionId: 'col2' }]
          }
        ]
      };

      vi.mocked(MongoChatItem.findOne).mockReturnValue({
        lean: () => Promise.resolve(mockChatItem)
      } as any);
      vi.mocked(getFlatAppResponses).mockReturnValue([
        { quoteList: [{ collectionId: 'col1' }, { collectionId: 'col2' }] }
      ]);

      await expect(
        authCollectionInChat({
          collectionIds: ['col1', 'col2', 'col3'], // col3 not found
          appId: 'app1',
          chatId: 'chat1',
          chatItemDataId: 'item1'
        })
      ).rejects.toBe(DatasetErrEnum.unAuthDatasetFile);
    });

    it('should handle quotes with missing collectionId', async () => {
      const mockChatItem = {
        time: new Date(),
        responseData: [
          {
            quoteList: [
              { collectionId: 'col1' },
              {
                /* missing collectionId */
              }
            ]
          }
        ]
      };

      vi.mocked(MongoChatItem.findOne).mockReturnValue({
        lean: () => Promise.resolve(mockChatItem)
      } as any);
      vi.mocked(getFlatAppResponses).mockReturnValue([
        { quoteList: [{ collectionId: 'col1' }, {}] }
      ]);

      const result = await authCollectionInChat({
        collectionIds: ['col1'],
        appId: 'app1',
        chatId: 'chat1',
        chatItemDataId: 'item1'
      });

      expect(result).toEqual(undefined);
    });

    it('should handle missing quoteList in response data', async () => {
      const mockChatItem = {
        time: new Date(),
        responseData: [
          {
            // no quoteList
          }
        ]
      };

      vi.mocked(MongoChatItem.findOne).mockReturnValue({
        lean: () => Promise.resolve(mockChatItem)
      } as any);
      vi.mocked(getFlatAppResponses).mockReturnValue([]);

      await expect(
        authCollectionInChat({
          collectionIds: ['col1'],
          appId: 'app1',
          chatId: 'chat1',
          chatItemDataId: 'item1'
        })
      ).rejects.toBe(DatasetErrEnum.unAuthDatasetFile);
    });
  });

  describe('error handling', () => {
    it('should reject if database query throws error', async () => {
      vi.mocked(MongoChatItem.findOne).mockImplementation(() => {
        throw new Error('Database error');
      });

      await expect(
        authCollectionInChat({
          collectionIds: ['col1'],
          appId: 'app1',
          chatId: 'chat1',
          chatItemDataId: 'item1'
        })
      ).rejects.toBe(DatasetErrEnum.unAuthDatasetFile);
    });

    it('should reject if getFlatAppResponses throws error', async () => {
      const mockChatItem = {
        time: new Date(),
        responseData: [{}]
      };

      vi.mocked(MongoChatItem.findOne).mockReturnValue({
        lean: () => Promise.resolve(mockChatItem)
      } as any);
      vi.mocked(getFlatAppResponses).mockImplementation(() => {
        throw new Error('Processing error');
      });

      await expect(
        authCollectionInChat({
          collectionIds: ['col1'],
          appId: 'app1',
          chatId: 'chat1',
          chatItemDataId: 'item1'
        })
      ).rejects.toBe(DatasetErrEnum.unAuthDatasetFile);
    });
  });
});
