import { Test, TestingModule } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { DataSource, Repository } from 'typeorm';
import { PermissionException } from '../../common/exceptions';
import { CorrespondenceService } from './correspondence.service';
import { Correspondence } from './entities/correspondence.entity';
import { CorrespondenceRevision } from './entities/correspondence-revision.entity';
import { CorrespondenceType } from './entities/correspondence-type.entity';
import { CorrespondenceStatus } from './entities/correspondence-status.entity';
import { CorrespondenceReference } from './entities/correspondence-reference.entity';
import { CorrespondenceTag } from './entities/correspondence-tag.entity';
import { Organization } from '../organization/entities/organization.entity';
import { CorrespondenceRecipient } from './entities/correspondence-recipient.entity';
import { CorrespondenceRevisionAttachment } from './entities/correspondence-revision-attachment.entity';
import { DocumentNumberingService } from '../document-numbering/services/document-numbering.service';
import { JsonSchemaService } from '../json-schema/json-schema.service';
import { WorkflowEngineService } from '../workflow-engine/workflow-engine.service';
import { UserService } from '../user/user.service';
import { SearchService } from '../search/search.service';
import { FileStorageService } from '../../common/file-storage/file-storage.service';
import { UuidResolverService } from '../../common/services/uuid-resolver.service';
import { NotificationService } from '../notification/notification.service';
import { CirculationService } from '../circulation/circulation.service';
import { UpdateCorrespondenceDto } from './dto/update-correspondence.dto';
import { CreateCorrespondenceDto } from './dto/create-correspondence.dto';
import { User } from '../user/entities/user.entity';

describe('CorrespondenceService', () => {
  let service: CorrespondenceService;
  let numberingService: DocumentNumberingService;
  let correspondenceRepo: Repository<Correspondence>;
  let revisionRepo: Repository<CorrespondenceRevision>;
  let testingModule: TestingModule;
  let _dataSource: DataSource;

  const createMockRepository = () => ({
    find: jest.fn(),
    findOne: jest.fn(),
    create: jest.fn(),
    save: jest.fn(),
    update: jest.fn(),
    delete: jest.fn(),
    softDelete: jest.fn(),
    createQueryBuilder: jest.fn(() => ({
      leftJoinAndSelect: jest.fn().mockReturnThis(),
      where: jest.fn().mockReturnThis(),
      andWhere: jest.fn().mockReturnThis(),
      orderBy: jest.fn().mockReturnThis(),
      skip: jest.fn().mockReturnThis(),
      take: jest.fn().mockReturnThis(),
      getOne: jest.fn().mockResolvedValue(null),
      getMany: jest.fn().mockResolvedValue([]),
      getManyAndCount: jest.fn().mockResolvedValue([[], 0]),
    })),
  });

  const mockManager = {
    create: jest.fn(),
    save: jest.fn(),
    findOne: jest.fn(),
    update: jest.fn(),
    delete: jest.fn(),
    getRepository: jest.fn(() => createMockRepository()),
  };

  const mockDataSource = {
    createQueryRunner: jest.fn(() => ({
      connect: jest.fn(),
      startTransaction: jest.fn(),
      commitTransaction: jest.fn(),
      rollbackTransaction: jest.fn(),
      release: jest.fn(),
      manager: mockManager,
    })),
    getRepository: jest.fn(() => createMockRepository()),
    manager: {
      findOne: jest.fn(),
    },
  };

  beforeEach(async () => {
    testingModule = await Test.createTestingModule({
      providers: [
        CorrespondenceService,
        {
          provide: getRepositoryToken(Correspondence),
          useValue: createMockRepository(),
        },
        {
          provide: getRepositoryToken(CorrespondenceRevision),
          useValue: createMockRepository(),
        },
        {
          provide: getRepositoryToken(CorrespondenceType),
          useValue: createMockRepository(),
        },
        {
          provide: getRepositoryToken(CorrespondenceStatus),
          useValue: createMockRepository(),
        },
        {
          provide: getRepositoryToken(CorrespondenceReference),
          useValue: createMockRepository(),
        },
        {
          provide: getRepositoryToken(CorrespondenceTag),
          useValue: createMockRepository(),
        },
        {
          provide: getRepositoryToken(Organization),
          useValue: createMockRepository(),
        },
        {
          provide: getRepositoryToken(CorrespondenceRecipient),
          useValue: createMockRepository(),
        },
        {
          provide: DocumentNumberingService,
          useValue: {
            generateNextNumber: jest.fn(),
            updateNumberForDraft: jest.fn(),
            previewNextNumber: jest.fn(),
          },
        },
        {
          provide: JsonSchemaService,
          useValue: { validate: jest.fn() },
        },
        {
          provide: WorkflowEngineService,
          useValue: {
            createInstance: jest.fn(),
            getInstanceByEntity: jest.fn().mockResolvedValue(null),
          },
        },
        {
          provide: UserService,
          useValue: {
            findOne: jest.fn(),
            getUserPermissions: jest.fn().mockResolvedValue([]),
          },
        },
        {
          provide: DataSource,
          useValue: mockDataSource,
        },
        {
          provide: SearchService,
          useValue: { indexDocument: jest.fn().mockResolvedValue(undefined) },
        },
        {
          provide: FileStorageService,
          useValue: { commit: jest.fn().mockResolvedValue([]) },
        },
        {
          provide: UuidResolverService,
          useValue: {
            resolveProjectId: jest.fn().mockResolvedValue(1),
            resolveOrganizationId: jest.fn().mockResolvedValue(1),
          },
        },
        {
          provide: NotificationService,
          useValue: { send: jest.fn().mockResolvedValue(undefined) },
        },
        {
          provide: getRepositoryToken(CorrespondenceRevisionAttachment),
          useValue: createMockRepository(),
        },
        {
          provide: CirculationService,
          useValue: {
            forceClose: jest.fn().mockResolvedValue({ success: true }),
          },
        },
      ],
    }).compile();

    service = testingModule.get<CorrespondenceService>(CorrespondenceService);
    numberingService = testingModule.get<DocumentNumberingService>(
      DocumentNumberingService
    );
    correspondenceRepo = testingModule.get<Repository<Correspondence>>(
      getRepositoryToken(Correspondence)
    );
    revisionRepo = testingModule.get<Repository<CorrespondenceRevision>>(
      getRepositoryToken(CorrespondenceRevision)
    );
    _dataSource = testingModule.get<DataSource>(DataSource);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });

  describe('update', () => {
    it('should allow non-draft update for org-admin+ permissions', async () => {
      const mockUser = {
        user_id: 1,
        primaryOrganizationId: 10,
      } as unknown as User;

      const mockCorr = {
        id: 1,
        publicId: 'corr-uuid-1',
        correspondenceNumber: 'CORR-001',
        projectId: 1,
        createdAt: new Date(),
        recipients: [],
      };

      const mockRevision = {
        id: 100,
        correspondenceId: 1,
        isCurrent: true,
        statusId: 23,
        correspondence: mockCorr,
      };

      jest
        .spyOn(revisionRepo, 'findOne')
        .mockResolvedValue(mockRevision as unknown as CorrespondenceRevision);

      const statusRepo = testingModule.get<Repository<CorrespondenceStatus>>(
        getRepositoryToken(CorrespondenceStatus)
      );
      (statusRepo.findOne as jest.Mock).mockResolvedValue({
        id: 23,
        statusCode: 'SUBOWN',
      });

      const userService = testingModule.get<UserService>(UserService);
      (userService.getUserPermissions as jest.Mock).mockResolvedValue([
        'correspondence.cancel',
      ]);

      jest.spyOn(correspondenceRepo, 'findOne').mockResolvedValue({
        ...mockCorr,
        revisions: [],
      } as unknown as Correspondence);

      await expect(
        service.update(1, { subject: 'Updated Subject' }, mockUser)
      ).resolves.toBeDefined();
    });

    it('should reject non-draft update for non-admin permissions', async () => {
      const mockUser = {
        user_id: 2,
        primaryOrganizationId: 10,
      } as unknown as User;
      const mockRevision = {
        id: 101,
        correspondenceId: 2,
        isCurrent: true,
        statusId: 23,
      };

      jest
        .spyOn(revisionRepo, 'findOne')
        .mockResolvedValue(mockRevision as unknown as CorrespondenceRevision);

      const statusRepo = testingModule.get<Repository<CorrespondenceStatus>>(
        getRepositoryToken(CorrespondenceStatus)
      );
      (statusRepo.findOne as jest.Mock).mockResolvedValue({
        id: 23,
        statusCode: 'SUBOWN',
      });

      const userService = testingModule.get<UserService>(UserService);
      (userService.getUserPermissions as jest.Mock).mockResolvedValue([
        'correspondence.edit',
      ]);

      await expect(
        service.update(2, { subject: 'Should Fail' }, mockUser)
      ).rejects.toThrow(PermissionException);
    });

    it('should NOT regenerate number if critical fields unchanged', async () => {
      const mockUser = { id: 1, primaryOrganizationId: 10 } as unknown as User;

      const mockCorr = {
        id: 1,
        projectId: 1,
        correspondenceTypeId: 2,
        disciplineId: 3,
        originatorId: 10,
        correspondenceNumber: 'OLD-NUM',
        recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }],
      };
      const mockRevision = {
        id: 100,
        correspondenceId: 1,
        isCurrent: true,
        statusId: 5,
        correspondence: mockCorr,
      };

      jest
        .spyOn(revisionRepo, 'findOne')
        .mockResolvedValue(mockRevision as unknown as CorrespondenceRevision);

      jest
        .spyOn(correspondenceRepo, 'findOne')
        .mockResolvedValue(mockCorr as unknown as Correspondence);

      const updateDto: UpdateCorrespondenceDto = {
        projectId: 1,
        disciplineId: 3,
      };

      await service.update(1, updateDto, mockUser);

      expect(
        numberingService.updateNumberForDraft as jest.Mock
      ).not.toHaveBeenCalled();
    });

    it('should regenerate number if Project ID changes', async () => {
      const mockUser = { id: 1, primaryOrganizationId: 10 } as unknown as User;
      const mockCorr = {
        id: 1,
        projectId: 1,
        correspondenceTypeId: 2,
        disciplineId: 3,
        originatorId: 10,
        correspondenceNumber: 'OLD-NUM',
        recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }],
      };
      const mockRevision = {
        id: 100,
        correspondenceId: 1,
        isCurrent: true,
        statusId: 5,
        correspondence: mockCorr,
      };
      jest
        .spyOn(revisionRepo, 'findOne')
        .mockResolvedValue(mockRevision as unknown as CorrespondenceRevision);

      const statusRepo = testingModule.get<Repository<CorrespondenceStatus>>(
        getRepositoryToken(CorrespondenceStatus)
      );
      (statusRepo.findOne as jest.Mock).mockResolvedValue({
        id: 5,
        statusCode: 'DRAFT',
      });

      const typeRepo = testingModule.get<Repository<CorrespondenceType>>(
        getRepositoryToken(CorrespondenceType)
      );
      (typeRepo.findOne as jest.Mock).mockResolvedValue({
        id: 2,
        typeCode: 'OLD-TYPE',
      });

      const updateDto: UpdateCorrespondenceDto = {
        projectId: 2,
      };

      const uuidResolver =
        testingModule.get<UuidResolverService>(UuidResolverService);
      (uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(2);

      jest.spyOn(correspondenceRepo, 'findOne').mockResolvedValue({
        ...mockCorr,
        projectId: 2,
      } as unknown as Correspondence);

      await service.update(1, updateDto, mockUser);

      expect(
        numberingService.updateNumberForDraft as jest.Mock
      ).toHaveBeenCalled();
    });

    it('should regenerate number if Document Type changes', async () => {
      const mockUser = { id: 1, primaryOrganizationId: 10 } as unknown as User;
      const mockCorr = {
        id: 1,
        projectId: 1,
        correspondenceTypeId: 2,
        disciplineId: 3,
        originatorId: 10,
        correspondenceNumber: 'OLD-NUM',
        recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }],
      };
      const mockRevision = {
        id: 100,
        correspondenceId: 1,
        isCurrent: true,
        statusId: 5,
        correspondence: mockCorr,
      };
      jest
        .spyOn(revisionRepo, 'findOne')
        .mockResolvedValue(mockRevision as unknown as CorrespondenceRevision);

      const statusRepo = testingModule.get<Repository<CorrespondenceStatus>>(
        getRepositoryToken(CorrespondenceStatus)
      );
      (statusRepo.findOne as jest.Mock).mockResolvedValue({
        id: 5,
        statusCode: 'DRAFT',
      });

      const typeRepo = testingModule.get<Repository<CorrespondenceType>>(
        getRepositoryToken(CorrespondenceType)
      );
      (typeRepo.findOne as jest.Mock).mockResolvedValue({
        id: 999,
        typeCode: 'NEW-TYPE',
      });

      const updateDto: UpdateCorrespondenceDto = {
        typeId: 999,
      };

      jest.spyOn(correspondenceRepo, 'findOne').mockResolvedValue({
        ...mockCorr,
        correspondenceTypeId: 999,
      } as unknown as Correspondence);

      await service.update(1, updateDto, mockUser);

      expect(
        numberingService.updateNumberForDraft as jest.Mock
      ).toHaveBeenCalled();
    });

    it('should regenerate number if Recipient Organization changes', async () => {
      const mockUser = { id: 1, primaryOrganizationId: 10 } as unknown as User;
      const mockCorr = {
        id: 1,
        projectId: 1,
        correspondenceTypeId: 2,
        disciplineId: 3,
        originatorId: 10,
        correspondenceNumber: 'OLD-NUM',
        recipients: [{ recipientType: 'TO', recipientOrganizationId: 99 }],
      };
      const mockRevision = {
        id: 100,
        correspondenceId: 1,
        isCurrent: true,
        statusId: 5,
        correspondence: mockCorr,
      };
      jest
        .spyOn(revisionRepo, 'findOne')
        .mockResolvedValue(mockRevision as unknown as CorrespondenceRevision);

      const typeRepo = testingModule.get<Repository<CorrespondenceType>>(
        getRepositoryToken(CorrespondenceType)
      );
      (typeRepo.findOne as jest.Mock).mockResolvedValue({
        id: 2,
        typeCode: 'OLD-TYPE',
      });

      const statusRepo = testingModule.get<Repository<CorrespondenceStatus>>(
        getRepositoryToken(CorrespondenceStatus)
      );
      (statusRepo.findOne as jest.Mock).mockResolvedValue({
        id: 5,
        statusCode: 'DRAFT',
      });

      // Access DataSource manager for mocking
      mockDataSource.manager.findOne.mockResolvedValue({
        id: 88,
        organizationCode: 'NEW-ORG',
      } as unknown as Organization);

      const updateDto: UpdateCorrespondenceDto = {
        recipients: [{ type: 'TO', organizationId: 88 }],
      };

      jest.spyOn(correspondenceRepo, 'findOne').mockResolvedValue({
        ...mockCorr,
        recipients: [{ recipientType: 'TO', recipientOrganizationId: 88 }],
      } as unknown as Correspondence);

      await service.update(1, updateDto, mockUser);

      expect(
        numberingService.updateNumberForDraft as jest.Mock
      ).toHaveBeenCalled();
    });
  });

  describe('create', () => {
    it('should allow system.manage_all user without primaryOrganizationId when originatorId is provided', async () => {
      const mockUser = {
        user_id: 1,
        primaryOrganizationId: null,
      } as unknown as User;

      const createDto: CreateCorrespondenceDto = {
        projectId: 'project-uuid',
        typeId: 1,
        subject: 'Test Subject',
        originatorId: 'originator-uuid',
        recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }],
      };

      const userService = testingModule.get<UserService>(UserService);
      const typeRepo = testingModule.get<Repository<CorrespondenceType>>(
        getRepositoryToken(CorrespondenceType)
      );
      const statusRepo = testingModule.get<Repository<CorrespondenceStatus>>(
        getRepositoryToken(CorrespondenceStatus)
      );
      const uuidResolver =
        testingModule.get<UuidResolverService>(UuidResolverService);

      (userService.findOne as jest.Mock).mockResolvedValue({
        user_id: 1,
        primaryOrganizationId: null,
      });
      (userService.getUserPermissions as jest.Mock).mockResolvedValue([
        'system.manage_all',
      ]);

      (uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(100);
      (uuidResolver.resolveOrganizationId as jest.Mock).mockImplementation(
        (value: number | string) => {
          if (value === 'originator-uuid') return 10;
          if (value === 'recipient-uuid') return 20;
          return 0;
        }
      );

      (typeRepo.findOne as jest.Mock).mockResolvedValue({
        id: 1,
        typeCode: 'LTR',
      });
      (statusRepo.findOne as jest.Mock).mockResolvedValue({
        id: 1,
        statusCode: 'DRAFT',
      });

      (numberingService.generateNextNumber as jest.Mock).mockResolvedValue({
        number: 'DOC-001',
      });

      mockDataSource.manager.findOne
        .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' })
        .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' });

      const queryRunner = {
        connect: jest.fn(),
        startTransaction: jest.fn(),
        commitTransaction: jest.fn(),
        rollbackTransaction: jest.fn(),
        release: jest.fn(),
        manager: {
          create: jest.fn(
            (_entity: unknown, payload: Record<string, unknown>) => payload
          ),
          save: jest
            .fn()
            .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' })
            .mockResolvedValueOnce({ id: 1000 })
            .mockResolvedValueOnce([]),
          findOne: jest.fn(),
        },
      };

      (mockDataSource.createQueryRunner as jest.Mock).mockReturnValue(
        queryRunner
      );

      await service.create(createDto, mockUser);

      expect(queryRunner.manager.create).toHaveBeenCalledWith(
        Correspondence,
        expect.objectContaining({ originatorId: 10 })
      );
    });

    it('should set revisionLabel to "A" for RFA type', async () => {
      const mockUser = {
        user_id: 1,
        primaryOrganizationId: 10,
      } as unknown as User;

      const createDto: CreateCorrespondenceDto = {
        projectId: 'project-uuid',
        typeId: 1,
        subject: 'Test Subject',
        recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }],
      };

      const typeRepo = testingModule.get<Repository<CorrespondenceType>>(
        getRepositoryToken(CorrespondenceType)
      );
      const statusRepo = testingModule.get<Repository<CorrespondenceStatus>>(
        getRepositoryToken(CorrespondenceStatus)
      );
      const uuidResolver =
        testingModule.get<UuidResolverService>(UuidResolverService);

      (uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(100);
      (uuidResolver.resolveOrganizationId as jest.Mock).mockResolvedValue(20);

      (typeRepo.findOne as jest.Mock).mockResolvedValue({
        id: 1,
        typeCode: 'RFA',
      });
      (statusRepo.findOne as jest.Mock).mockResolvedValue({
        id: 1,
        statusCode: 'DRAFT',
      });

      (numberingService.generateNextNumber as jest.Mock).mockResolvedValue({
        number: 'DOC-001',
      });

      mockDataSource.manager.findOne
        .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' })
        .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' });

      const queryRunner = {
        connect: jest.fn(),
        startTransaction: jest.fn(),
        commitTransaction: jest.fn(),
        rollbackTransaction: jest.fn(),
        release: jest.fn(),
        manager: {
          create: jest.fn(
            (_entity: unknown, payload: Record<string, unknown>) => payload
          ),
          save: jest
            .fn()
            .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' })
            .mockResolvedValueOnce({ id: 1000 })
            .mockResolvedValueOnce([]),
          findOne: jest.fn(),
        },
      };

      (mockDataSource.createQueryRunner as jest.Mock).mockReturnValue(
        queryRunner
      );

      await service.create(createDto, mockUser);

      expect(queryRunner.manager.create).toHaveBeenCalledWith(
        CorrespondenceRevision,
        expect.objectContaining({ revisionLabel: 'A' })
      );
    });

    it('should set revisionLabel to "A" for RFI type', async () => {
      const mockUser = {
        user_id: 1,
        primaryOrganizationId: 10,
      } as unknown as User;

      const createDto: CreateCorrespondenceDto = {
        projectId: 'project-uuid',
        typeId: 1,
        subject: 'Test Subject',
        recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }],
      };

      const typeRepo = testingModule.get<Repository<CorrespondenceType>>(
        getRepositoryToken(CorrespondenceType)
      );
      const statusRepo = testingModule.get<Repository<CorrespondenceStatus>>(
        getRepositoryToken(CorrespondenceStatus)
      );
      const uuidResolver =
        testingModule.get<UuidResolverService>(UuidResolverService);

      (uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(100);
      (uuidResolver.resolveOrganizationId as jest.Mock).mockResolvedValue(20);

      (typeRepo.findOne as jest.Mock).mockResolvedValue({
        id: 1,
        typeCode: 'RFI',
      });
      (statusRepo.findOne as jest.Mock).mockResolvedValue({
        id: 1,
        statusCode: 'DRAFT',
      });

      (numberingService.generateNextNumber as jest.Mock).mockResolvedValue({
        number: 'DOC-001',
      });

      mockDataSource.manager.findOne
        .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' })
        .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' });

      const queryRunner = {
        connect: jest.fn(),
        startTransaction: jest.fn(),
        commitTransaction: jest.fn(),
        rollbackTransaction: jest.fn(),
        release: jest.fn(),
        manager: {
          create: jest.fn(
            (_entity: unknown, payload: Record<string, unknown>) => payload
          ),
          save: jest
            .fn()
            .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' })
            .mockResolvedValueOnce({ id: 1000 })
            .mockResolvedValueOnce([]),
          findOne: jest.fn(),
        },
      };

      (mockDataSource.createQueryRunner as jest.Mock).mockReturnValue(
        queryRunner
      );

      await service.create(createDto, mockUser);

      expect(queryRunner.manager.create).toHaveBeenCalledWith(
        CorrespondenceRevision,
        expect.objectContaining({ revisionLabel: 'A' })
      );
    });

    it('should set revisionLabel to null for LETTER type', async () => {
      const mockUser = {
        user_id: 1,
        primaryOrganizationId: 10,
      } as unknown as User;

      const createDto: CreateCorrespondenceDto = {
        projectId: 'project-uuid',
        typeId: 1,
        subject: 'Test Subject',
        recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }],
      };

      const typeRepo = testingModule.get<Repository<CorrespondenceType>>(
        getRepositoryToken(CorrespondenceType)
      );
      const statusRepo = testingModule.get<Repository<CorrespondenceStatus>>(
        getRepositoryToken(CorrespondenceStatus)
      );
      const uuidResolver =
        testingModule.get<UuidResolverService>(UuidResolverService);

      (uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(100);
      (uuidResolver.resolveOrganizationId as jest.Mock).mockResolvedValue(20);

      (typeRepo.findOne as jest.Mock).mockResolvedValue({
        id: 1,
        typeCode: 'LETTER',
      });
      (statusRepo.findOne as jest.Mock).mockResolvedValue({
        id: 1,
        statusCode: 'DRAFT',
      });

      (numberingService.generateNextNumber as jest.Mock).mockResolvedValue({
        number: 'DOC-001',
      });

      mockDataSource.manager.findOne
        .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' })
        .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' });

      const queryRunner = {
        connect: jest.fn(),
        startTransaction: jest.fn(),
        commitTransaction: jest.fn(),
        rollbackTransaction: jest.fn(),
        release: jest.fn(),
        manager: {
          create: jest.fn(
            (_entity: unknown, payload: Record<string, unknown>) => payload
          ),
          save: jest
            .fn()
            .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' })
            .mockResolvedValueOnce({ id: 1000 })
            .mockResolvedValueOnce([]),
          findOne: jest.fn(),
        },
      };

      (mockDataSource.createQueryRunner as jest.Mock).mockReturnValue(
        queryRunner
      );

      await service.create(createDto, mockUser);

      expect(queryRunner.manager.create).toHaveBeenCalledWith(
        CorrespondenceRevision,
        expect.objectContaining({ revisionLabel: undefined })
      );
    });

    it('should set revisionLabel to undefined for MEMO type', async () => {
      const mockUser = {
        user_id: 1,
        primaryOrganizationId: 10,
      } as unknown as User;

      const createDto: CreateCorrespondenceDto = {
        projectId: 'project-uuid',
        typeId: 1,
        subject: 'Test Subject',
        recipients: [{ organizationId: 'recipient-uuid', type: 'TO' }],
      };

      const typeRepo = testingModule.get<Repository<CorrespondenceType>>(
        getRepositoryToken(CorrespondenceType)
      );
      const statusRepo = testingModule.get<Repository<CorrespondenceStatus>>(
        getRepositoryToken(CorrespondenceStatus)
      );
      const uuidResolver =
        testingModule.get<UuidResolverService>(UuidResolverService);

      (uuidResolver.resolveProjectId as jest.Mock).mockResolvedValue(100);
      (uuidResolver.resolveOrganizationId as jest.Mock).mockResolvedValue(20);

      (typeRepo.findOne as jest.Mock).mockResolvedValue({
        id: 1,
        typeCode: 'MEMO',
      });
      (statusRepo.findOne as jest.Mock).mockResolvedValue({
        id: 1,
        statusCode: 'DRAFT',
      });

      (numberingService.generateNextNumber as jest.Mock).mockResolvedValue({
        number: 'DOC-001',
      });

      mockDataSource.manager.findOne
        .mockResolvedValueOnce({ id: 10, organizationCode: 'ORG' })
        .mockResolvedValueOnce({ id: 20, organizationCode: 'REC' });

      const queryRunner = {
        connect: jest.fn(),
        startTransaction: jest.fn(),
        commitTransaction: jest.fn(),
        rollbackTransaction: jest.fn(),
        release: jest.fn(),
        manager: {
          create: jest.fn(
            (_entity: unknown, payload: Record<string, unknown>) => payload
          ),
          save: jest
            .fn()
            .mockResolvedValueOnce({ id: 999, publicId: 'corr-uuid' })
            .mockResolvedValueOnce({ id: 1000 })
            .mockResolvedValueOnce([]),
          findOne: jest.fn(),
        },
      };

      (mockDataSource.createQueryRunner as jest.Mock).mockReturnValue(
        queryRunner
      );

      await service.create(createDto, mockUser);

      expect(queryRunner.manager.create).toHaveBeenCalledWith(
        CorrespondenceRevision,
        expect.objectContaining({ revisionLabel: undefined })
      );
    });
  });
});
