import { Result } from '@core/racing/domain/entities/result/Result';

import { ResultOrmEntity } from '../entities/ResultOrmEntity';
import { InvalidResultSchemaError } from '../errors/InvalidResultSchemaError';
import { TypeOrmPersistenceSchemaError } from '../errors/TypeOrmPersistenceSchemaError';
import { assertInteger, assertNonEmptyString } from '../schema/TypeOrmSchemaGuards';

export class ResultOrmMapper {
  toOrmEntity(domain: Result): ResultOrmEntity {
    const entity = new ResultOrmEntity();
    entity.id = domain.id;
    entity.raceId = domain.raceId.toString();
    entity.driverId = domain.driverId.toString();
    entity.position = domain.position.toNumber();
    entity.fastestLap = domain.fastestLap.toNumber();
    entity.incidents = domain.incidents.toNumber();
    entity.startPosition = domain.startPosition.toNumber();
    return entity;
  }

  toDomain(entity: ResultOrmEntity): Result {
    const entityName = 'Result';

    try {
      assertNonEmptyString(entityName, 'id', entity.id);
      assertNonEmptyString(entityName, 'raceId', entity.raceId);
      assertNonEmptyString(entityName, 'driverId', entity.driverId);
      assertInteger(entityName, 'position', entity.position);
      assertInteger(entityName, 'fastestLap', entity.fastestLap);
      assertInteger(entityName, 'incidents', entity.incidents);
      assertInteger(entityName, 'startPosition', entity.startPosition);
    } catch (error) {
      if (error instanceof TypeOrmPersistenceSchemaError) {
        throw new InvalidResultSchemaError({
          fieldName: error.fieldName,
          reason: error.reason,
          message: error.message,
        });
      }
      throw error;
    }

    try {
      return Result.rehydrate({
        id: entity.id,
        raceId: entity.raceId,
        driverId: entity.driverId,
        position: entity.position,
        fastestLap: entity.fastestLap,
        incidents: entity.incidents,
        startPosition: entity.startPosition,
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Invalid persisted Result';
      throw new InvalidResultSchemaError({
        fieldName: 'unknown',
        reason: 'invalid_shape',
        message,
      });
    }
  }
}