import { Notification } from '@core/notifications/domain/entities/Notification';
import { NotificationOrmEntity } from '../entities/NotificationOrmEntity';
import { TypeOrmPersistenceSchemaError } from '../errors/TypeOrmPersistenceSchemaError';
import {
    assertBoolean,
    assertDate,
    assertNonEmptyString,
    assertNotificationActions,
    assertNotificationChannel,
    assertNotificationStatus,
    assertNotificationType,
    assertNotificationUrgency,
    assertOptionalDate,
    assertOptionalObject,
    assertOptionalStringOrNull,
} from '../schema/NotificationSchemaGuards';

export class NotificationOrmMapper {
  toDomain(entity: NotificationOrmEntity): Notification {
    const entityName = 'Notification';

    try {
      assertNonEmptyString(entityName, 'id', entity.id);
      assertNonEmptyString(entityName, 'recipientId', entity.recipientId);
      assertNotificationType(entityName, 'type', entity.type);
      assertNonEmptyString(entityName, 'title', entity.title);
      assertNonEmptyString(entityName, 'body', entity.body);
      assertNotificationChannel(entityName, 'channel', entity.channel);
      assertNotificationStatus(entityName, 'status', entity.status);
      assertNotificationUrgency(entityName, 'urgency', entity.urgency);
      assertDate(entityName, 'createdAt', entity.createdAt);
      assertOptionalDate(entityName, 'readAt', entity.readAt);
      assertOptionalDate(entityName, 'respondedAt', entity.respondedAt);
      assertOptionalStringOrNull(entityName, 'actionUrl', entity.actionUrl);
      assertOptionalObject(entityName, 'data', entity.data);
      assertNotificationActions(entityName, 'actions', entity.actions);
      assertBoolean(entityName, 'requiresResponse', entity.requiresResponse);
    } catch (error) {
      if (error instanceof TypeOrmPersistenceSchemaError) {
        throw error;
      }
      const message = error instanceof Error ? error.message : 'Invalid persisted Notification';
      throw new TypeOrmPersistenceSchemaError({ entityName, fieldName: 'unknown', reason: 'invalid_shape', message });
    }

    try {
      const domainProps: any = {
        id: entity.id,
        recipientId: entity.recipientId,
        type: entity.type,
        title: entity.title,
        body: entity.body,
        channel: entity.channel,
        status: entity.status,
        urgency: entity.urgency,
        createdAt: entity.createdAt,
        requiresResponse: entity.requiresResponse,
      };

      if (entity.data !== null && entity.data !== undefined) {
        domainProps.data = entity.data as Record<string, unknown>;
      }

      if (entity.actionUrl !== null && entity.actionUrl !== undefined) {
        domainProps.actionUrl = entity.actionUrl;
      }

      if (entity.actions !== null && entity.actions !== undefined) {
        domainProps.actions = entity.actions;
      }

      if (entity.readAt !== null && entity.readAt !== undefined) {
        domainProps.readAt = entity.readAt;
      }

      if (entity.respondedAt !== null && entity.respondedAt !== undefined) {
        domainProps.respondedAt = entity.respondedAt;
      }

      return Notification.create(domainProps);
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Invalid persisted Notification';
      throw new TypeOrmPersistenceSchemaError({ entityName, fieldName: 'unknown', reason: 'invalid_shape', message });
    }
  }

  toOrmEntity(notification: Notification): NotificationOrmEntity {
    const entity = new NotificationOrmEntity();
    const props = notification.toJSON();

    entity.id = props.id;
    entity.recipientId = props.recipientId;
    entity.type = props.type;
    entity.title = props.title;
    entity.body = props.body;
    entity.channel = props.channel;
    entity.status = props.status;
    entity.urgency = props.urgency;
    entity.data = props.data ?? null;
    entity.actionUrl = props.actionUrl ?? null;
    entity.actions = props.actions ?? null;
    entity.requiresResponse = props.requiresResponse ?? false;
    entity.createdAt = props.createdAt;
    entity.readAt = props.readAt ?? null;
    entity.respondedAt = props.respondedAt ?? null;

    return entity;
  }

  toStored(entity: NotificationOrmEntity): Notification {
    return this.toDomain(entity);
  }
}