import { Test, TestingModule } from '@nestjs/testing';
import { ConfigModule } from '@nestjs/config';
import { PrismaService } from '../../../src/infrastructure/persistence/prisma/prisma.service';
import { AppVersionRepositoryImpl } from '../../../src/infrastructure/persistence/repositories/app-version.repository.impl';
import { AppVersionMapper } from '../../../src/infrastructure/persistence/mappers/app-version.mapper';
import { CreateVersionHandler } from '../../../src/application/commands/create-version/create-version.handler';
import { CreateVersionCommand } from '../../../src/application/commands/create-version/create-version.command';
import { APP_VERSION_REPOSITORY } from '../../../src/domain/repositories/app-version.repository';
import { Platform } from '../../../src/domain/enums/platform.enum';

describe('CreateVersionHandler Integration Tests', () => {
  let handler: CreateVersionHandler;
  let prisma: PrismaService;

  beforeAll(async () => {
    const module: TestingModule = await Test.createTestingModule({
      imports: [
        ConfigModule.forRoot({
          isGlobal: true,
          envFilePath: '.env.test',
        }),
      ],
      providers: [
        PrismaService,
        AppVersionMapper,
        {
          provide: APP_VERSION_REPOSITORY,
          useClass: AppVersionRepositoryImpl,
        },
        CreateVersionHandler,
      ],
    }).compile();

    handler = module.get<CreateVersionHandler>(CreateVersionHandler);
    prisma = module.get<PrismaService>(PrismaService);

    await prisma.$connect();
  });

  afterAll(async () => {
    await prisma.$disconnect();
  });

  beforeEach(async () => {
    await prisma.appVersion.deleteMany({});
  });

  describe('execute', () => {
    it('should create new Android version', async () => {
      const command = new CreateVersionCommand(
        Platform.ANDROID,
        100,
        '1.0.0',
        '100',
        'https://example.com/app.apk',
        10485760n,
        'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
        'Initial release with basic features',
        false,
        '5.0',
        null,
        'admin',
      );

      const result = await handler.execute(command);

      expect(result).toBeDefined();
      expect(result.platform).toBe(Platform.ANDROID);
      expect(result.versionCode.value).toBe(100);
      expect(result.versionName.value).toBe('1.0.0');
      expect(result.isEnabled).toBe(true);
      expect(result.isForceUpdate).toBe(false);
    });

    it('should create new iOS version', async () => {
      const command = new CreateVersionCommand(
        Platform.IOS,
        100,
        '1.0.0',
        '100',
        'https://example.com/app.ipa',
        15728640n,
        '0000000000000000000000000000000000000000000000000000000000000000',
        'iOS initial release',
        false,
        '14.0',
        null,
        'admin',
      );

      const result = await handler.execute(command);

      expect(result).toBeDefined();
      expect(result.platform).toBe(Platform.IOS);
      expect(result.versionCode.value).toBe(100);
    });

    it('should create version with force update flag', async () => {
      const command = new CreateVersionCommand(
        Platform.ANDROID,
        200,
        '2.0.0',
        '200',
        'https://example.com/app-v2.apk',
        20971520n,
        '1111111111111111111111111111111111111111111111111111111111111111',
        'Critical security update',
        true,
        '6.0',
        null,
        'admin',
      );

      const result = await handler.execute(command);

      expect(result.isForceUpdate).toBe(true);
    });

    it('should create version with release date', async () => {
      const releaseDate = new Date('2024-12-31');
      const command = new CreateVersionCommand(
        Platform.ANDROID,
        300,
        '3.0.0',
        '300',
        'https://example.com/app-v3.apk',
        31457280n,
        '2222222222222222222222222222222222222222222222222222222222222222',
        'Scheduled major release',
        false,
        '7.0',
        releaseDate,
        'admin',
      );

      const result = await handler.execute(command);

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

    it('should persist version to database', async () => {
      const command = new CreateVersionCommand(
        Platform.ANDROID,
        400,
        '4.0.0',
        '400',
        'https://example.com/app-v4.apk',
        41943040n,
        '3333333333333333333333333333333333333333333333333333333333333333',
        'Persistence test version',
        false,
        '8.0',
        null,
        'admin',
      );

      const result = await handler.execute(command);

      // Verify it's in database
      const found = await prisma.appVersion.findUnique({
        where: { id: result.id },
      });

      expect(found).not.toBeNull();
      expect(found!.versionCode).toBe(400);
      expect(found!.versionName).toBe('4.0.0');
    });
  });
});
