import type { FeedItem } from '@core/social/domain/types/FeedItem';
import type { FeedItemType } from '@core/social/domain/types/FeedItemType';

import { FeedItemOrmEntity } from '../entities/FeedItemOrmEntity';
import { TypeOrmSocialSchemaError } from '../errors/TypeOrmSocialSchemaError';
import {
    assertDate,
    assertEnumValue,
    assertNonEmptyString,
    assertOptionalIntegerOrNull,
    assertOptionalStringOrNull,
} from '../schema/TypeOrmSocialSchemaGuards';

export class FeedItemOrmMapper {
  toOrmEntity(domain: FeedItem): FeedItemOrmEntity {
    const entity = new FeedItemOrmEntity();
    entity.id = domain.id;
    entity.timestamp = domain.timestamp;
    entity.type = domain.type;

    entity.actorFriendId = domain.actorFriendId ?? null;
    entity.actorDriverId = domain.actorDriverId ?? null;
    entity.leagueId = domain.leagueId ?? null;
    entity.raceId = domain.raceId ?? null;
    entity.teamId = domain.teamId ?? null;

    entity.position = domain.position ?? null;

    entity.headline = domain.headline;
    entity.body = domain.body ?? null;
    entity.ctaLabel = domain.ctaLabel ?? null;
    entity.ctaHref = domain.ctaHref ?? null;

    return entity;
  }

  toDomain(entity: FeedItemOrmEntity): FeedItem {
    const entityName = 'SocialFeedItem';

    try {
      assertNonEmptyString(entityName, 'id', entity.id);
      assertDate(entityName, 'timestamp', entity.timestamp);

      assertEnumValue<FeedItemType>(
        entityName,
        'type',
        entity.type,
        [
          'friend-joined-league',
          'friend-joined-team',
          'friend-finished-race',
          'friend-new-personal-best',
          'new-race-scheduled',
          'new-result-posted',
          'league-highlight',
        ] as const,
      );

      assertOptionalStringOrNull(entityName, 'actorFriendId', entity.actorFriendId);
      assertOptionalStringOrNull(entityName, 'actorDriverId', entity.actorDriverId);
      assertOptionalStringOrNull(entityName, 'leagueId', entity.leagueId);
      assertOptionalStringOrNull(entityName, 'raceId', entity.raceId);
      assertOptionalStringOrNull(entityName, 'teamId', entity.teamId);

      assertOptionalIntegerOrNull(entityName, 'position', entity.position);

      assertNonEmptyString(entityName, 'headline', entity.headline);
      assertOptionalStringOrNull(entityName, 'body', entity.body);
      assertOptionalStringOrNull(entityName, 'ctaLabel', entity.ctaLabel);
      assertOptionalStringOrNull(entityName, 'ctaHref', entity.ctaHref);

      return {
        id: entity.id,
        timestamp: entity.timestamp,
        type: entity.type,
        ...(entity.actorFriendId !== null && entity.actorFriendId !== undefined
          ? { actorFriendId: entity.actorFriendId }
          : {}),
        ...(entity.actorDriverId !== null && entity.actorDriverId !== undefined
          ? { actorDriverId: entity.actorDriverId }
          : {}),
        ...(entity.leagueId !== null && entity.leagueId !== undefined ? { leagueId: entity.leagueId } : {}),
        ...(entity.raceId !== null && entity.raceId !== undefined ? { raceId: entity.raceId } : {}),
        ...(entity.teamId !== null && entity.teamId !== undefined ? { teamId: entity.teamId } : {}),
        ...(entity.position !== null && entity.position !== undefined ? { position: entity.position } : {}),
        headline: entity.headline,
        ...(entity.body !== null && entity.body !== undefined ? { body: entity.body } : {}),
        ...(entity.ctaLabel !== null && entity.ctaLabel !== undefined ? { ctaLabel: entity.ctaLabel } : {}),
        ...(entity.ctaHref !== null && entity.ctaHref !== undefined ? { ctaHref: entity.ctaHref } : {}),
      };
    } catch (error) {
      if (error instanceof TypeOrmSocialSchemaError) {
        throw error;
      }

      const message = error instanceof Error ? error.message : 'Invalid persisted SocialFeedItem';
      throw new TypeOrmSocialSchemaError({ entityName, fieldName: 'unknown', reason: 'invalid_shape', message });
    }
  }
}