import { AppVersion } from '../../../../src/domain/entities/app-version.entity';
import { Platform } from '../../../../src/domain/enums/platform.enum';
import { VersionCode } from '../../../../src/domain/value-objects/version-code.vo';
import { VersionName } from '../../../../src/domain/value-objects/version-name.vo';
import { BuildNumber } from '../../../../src/domain/value-objects/build-number.vo';
import { DownloadUrl } from '../../../../src/domain/value-objects/download-url.vo';
import { FileSize } from '../../../../src/domain/value-objects/file-size.vo';
import { FileSha256 } from '../../../../src/domain/value-objects/file-sha256.vo';
import { Changelog } from '../../../../src/domain/value-objects/changelog.vo';

describe('AppVersion Entity', () => {
  const createValidParams = () => ({
    platform: Platform.ANDROID,
    versionCode: VersionCode.create(100),
    versionName: VersionName.create('1.0.0'),
    buildNumber: BuildNumber.create('100'),
    downloadUrl: DownloadUrl.create('https://example.com/app.apk'),
    fileSize: FileSize.create(10485760n), // 10 MB
    fileSha256: FileSha256.create('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'),
    changelog: Changelog.create('Initial release with basic features'),
    isForceUpdate: false,
    createdBy: 'admin',
  });

  describe('create', () => {
    it('should create valid app version', () => {
      const params = createValidParams();
      const appVersion = AppVersion.create(params);

      expect(appVersion.id).toBeDefined();
      expect(appVersion.platform).toBe(Platform.ANDROID);
      expect(appVersion.versionCode).toBe(params.versionCode);
      expect(appVersion.versionName).toBe(params.versionName);
      expect(appVersion.isEnabled).toBe(true);
      expect(appVersion.isForceUpdate).toBe(false);
      expect(appVersion.releaseDate).toBeNull();
      expect(appVersion.createdBy).toBe('admin');
      expect(appVersion.createdAt).toBeInstanceOf(Date);
    });

    it('should create with optional min OS version', () => {
      const params = createValidParams();
      const appVersion = AppVersion.create({
        ...params,
        minOsVersion: null,
      });

      expect(appVersion.minOsVersion).toBeNull();
    });
  });

  describe('business methods', () => {
    describe('disable', () => {
      it('should disable the version', () => {
        const appVersion = AppVersion.create(createValidParams());
        const beforeUpdate = new Date(appVersion.updatedAt);

        appVersion.disable('admin');

        expect(appVersion.isEnabled).toBe(false);
        expect(appVersion.updatedBy).toBe('admin');
        expect(appVersion.updatedAt.getTime()).toBeGreaterThanOrEqual(beforeUpdate.getTime());
      });
    });

    describe('enable', () => {
      it('should enable the version', () => {
        const appVersion = AppVersion.create(createValidParams());
        appVersion.disable('admin');

        appVersion.enable('admin');

        expect(appVersion.isEnabled).toBe(true);
        expect(appVersion.updatedBy).toBe('admin');
      });
    });

    describe('setForceUpdate', () => {
      it('should set force update flag', () => {
        const appVersion = AppVersion.create(createValidParams());

        appVersion.setForceUpdate(true, 'admin');

        expect(appVersion.isForceUpdate).toBe(true);
        expect(appVersion.updatedBy).toBe('admin');
      });

      it('should unset force update flag', () => {
        const appVersion = AppVersion.create(createValidParams());
        appVersion.setForceUpdate(true, 'admin');

        appVersion.setForceUpdate(false, 'admin');

        expect(appVersion.isForceUpdate).toBe(false);
      });
    });

    describe('setReleaseDate', () => {
      it('should set release date', () => {
        const appVersion = AppVersion.create(createValidParams());
        const releaseDate = new Date('2024-01-01');

        appVersion.setReleaseDate(releaseDate, 'admin');

        expect(appVersion.releaseDate).toEqual(releaseDate);
        expect(appVersion.updatedBy).toBe('admin');
      });
    });
  });

  describe('query methods', () => {
    describe('isNewerThan', () => {
      it('should return true for newer version', () => {
        const oldVersion = AppVersion.create(createValidParams());
        const newParams = createValidParams();
        newParams.versionCode = VersionCode.create(200);
        const newVersion = AppVersion.create(newParams);

        expect(newVersion.isNewerThan(VersionCode.create(100))).toBe(true);
      });

      it('should return false for same or older version', () => {
        const version = AppVersion.create(createValidParams());

        expect(version.isNewerThan(VersionCode.create(100))).toBe(false);
        expect(version.isNewerThan(VersionCode.create(200))).toBe(false);
      });
    });

    describe('shouldForceUpdate', () => {
      it('should return true when force update is enabled', () => {
        const appVersion = AppVersion.create(createValidParams());
        appVersion.setForceUpdate(true, 'admin');

        expect(appVersion.shouldForceUpdate()).toBe(true);
      });

      it('should return false when force update is disabled', () => {
        const appVersion = AppVersion.create(createValidParams());

        expect(appVersion.shouldForceUpdate()).toBe(false);
      });
    });
  });

  describe('reconstitute', () => {
    it('should reconstitute from persistence', () => {
      const id = 'test-id';
      const createdAt = new Date('2024-01-01');
      const updatedAt = new Date('2024-01-02');

      const appVersion = AppVersion.reconstitute({
        id,
        ...createValidParams(),
        isEnabled: true,
        isForceUpdate: false,
        minOsVersion: null,
        releaseDate: null,
        createdAt,
        updatedAt,
        updatedBy: null,
      });

      expect(appVersion.id).toBe(id);
      expect(appVersion.createdAt).toEqual(createdAt);
      expect(appVersion.updatedAt).toEqual(updatedAt);
    });
  });
});
