import { describe, expect, it } from 'vitest';

import { NotificationPreference } from '@core/notifications/domain/entities/NotificationPreference';

import { NotificationPreferenceOrmEntity } from '../entities/NotificationPreferenceOrmEntity';
import { TypeOrmPersistenceSchemaError } from '../errors/TypeOrmPersistenceSchemaError';
import { NotificationPreferenceOrmMapper } from './NotificationPreferenceOrmMapper';

describe('NotificationPreferenceOrmMapper', () => {
  it('toDomain preserves persisted identity and uses reconstitute semantics', () => {
    const mapper = new NotificationPreferenceOrmMapper();

    const entity = new NotificationPreferenceOrmEntity();
    entity.id = 'driver-123';
    entity.driverId = 'driver-123';
    entity.channels = {
      in_app: { enabled: true },
      email: { enabled: false },
      discord: { enabled: false },
      push: { enabled: false },
    };
    entity.typePreferences = {
      race_reminder: { enabled: true, channels: ['in_app'] },
    };
    entity.digestMode = false;
    entity.digestFrequencyHours = null;
    entity.quietHoursStart = null;
    entity.quietHoursEnd = null;
    entity.createdAt = new Date('2025-01-01T00:00:00.000Z');
    entity.updatedAt = new Date('2025-01-01T00:00:00.000Z');

    const domain = mapper.toDomain(entity);

    expect(domain.id).toBe(entity.id);
    expect(domain.driverId).toBe(entity.driverId);
    expect(domain.channels).toEqual(entity.channels);
    expect(domain.typePreferences).toEqual(entity.typePreferences);
    expect(domain.digestMode).toBe(false);
  });

  it('toDomain validates persisted shape and throws adapter-scoped schema error', () => {
    const mapper = new NotificationPreferenceOrmMapper();

    const entity = new NotificationPreferenceOrmEntity();
    entity.id = 'driver-123';
    entity.driverId = 123 as unknown as string; // Invalid
    entity.channels = {
      in_app: { enabled: true },
      email: { enabled: false },
      discord: { enabled: false },
      push: { enabled: false },
    };
    entity.typePreferences = null;
    entity.digestMode = false;
    entity.digestFrequencyHours = null;
    entity.quietHoursStart = null;
    entity.quietHoursEnd = null;
    entity.createdAt = new Date('2025-01-01T00:00:00.000Z');
    entity.updatedAt = new Date('2025-01-01T00:00:00.000Z');

    try {
      mapper.toDomain(entity);
      throw new Error('expected-to-throw');
    } catch (error) {
      expect(error).toBeInstanceOf(TypeOrmPersistenceSchemaError);
      expect(error).toMatchObject({
        entityName: 'NotificationPreference',
        fieldName: 'driverId',
        reason: 'invalid_string',
      });
    }
  });

  it('toOrmEntity converts domain entity to ORM entity', () => {
    const mapper = new NotificationPreferenceOrmMapper();

    const domain = NotificationPreference.create({
      id: 'driver-123',
      driverId: 'driver-123',
      channels: {
        in_app: { enabled: true },
        email: { enabled: false },
        discord: { enabled: false },
        push: { enabled: false },
      },
      typePreferences: {
        race_reminder: { enabled: true, channels: ['in_app'] },
      },
      digestMode: false,
      updatedAt: new Date('2025-01-01T00:00:00.000Z'),
    });

    const entity = mapper.toOrmEntity(domain);

    expect(entity.id).toBe(domain.id);
    expect(entity.driverId).toBe(domain.driverId);
    expect(entity.channels).toEqual(domain.channels);
    expect(entity.typePreferences).toEqual(domain.typePreferences);
    expect(entity.digestMode).toBe(false);
    expect(entity.updatedAt).toEqual(domain.updatedAt);
  });

  it('toDomain handles all optional fields as null', () => {
    const mapper = new NotificationPreferenceOrmMapper();

    const entity = new NotificationPreferenceOrmEntity();
    entity.id = 'driver-123';
    entity.driverId = 'driver-123';
    entity.channels = {
      in_app: { enabled: true },
      email: { enabled: true, settings: { emailAddress: 'test@example.com' } },
      discord: { enabled: false },
      push: { enabled: false },
    };
    entity.typePreferences = null;
    entity.digestMode = true;
    entity.digestFrequencyHours = 24;
    entity.quietHoursStart = 22;
    entity.quietHoursEnd = 8;
    entity.createdAt = new Date('2025-01-01T00:00:00.000Z');
    entity.updatedAt = new Date('2025-01-01T00:00:00.000Z');

    const domain = mapper.toDomain(entity);

    expect(domain.typePreferences).toBeUndefined();
    expect(domain.digestMode).toBe(true);
    expect(domain.digestFrequencyHours).toBe(24);
    expect(domain.quietHoursStart).toBe(22);
    expect(domain.quietHoursEnd).toBe(8);
    expect(domain.channels.email.settings?.emailAddress).toBe('test@example.com');
  });

  it('toDomain handles default preferences', () => {
    const mapper = new NotificationPreferenceOrmMapper();

    const entity = new NotificationPreferenceOrmEntity();
    entity.id = 'driver-456';
    entity.driverId = 'driver-456';
    entity.channels = {
      in_app: { enabled: true },
      email: { enabled: false },
      discord: { enabled: false },
      push: { enabled: false },
    };
    entity.typePreferences = null;
    entity.digestMode = false;
    entity.digestFrequencyHours = null;
    entity.quietHoursStart = null;
    entity.quietHoursEnd = null;
    entity.createdAt = new Date('2025-01-01T00:00:00.000Z');
    entity.updatedAt = new Date('2025-01-01T00:00:00.000Z');

    const domain = mapper.toDomain(entity);

    expect(domain.isChannelEnabled('in_app')).toBe(true);
    expect(domain.isChannelEnabled('email')).toBe(false);
    expect(domain.isTypeEnabled('race_reminder')).toBe(true); // Default to enabled
  });
});