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

import { LeagueScoringConfigOrmEntity } from '../entities/LeagueScoringConfigOrmEntity';
import { assertArray, assertNonEmptyString, assertRecord } from '../schema/TypeOrmSchemaGuards';
import { ChampionshipConfigJsonMapper, type SerializedChampionshipConfig } from './ChampionshipConfigJsonMapper';

function assertSerializedChampionshipConfig(value: unknown, index: number): asserts value is SerializedChampionshipConfig {
  const entityName = 'LeagueScoringConfig';
  const fieldBase = `championships[${index}]`;

  assertRecord(entityName, fieldBase, value);

  assertNonEmptyString(entityName, `${fieldBase}.id`, value.id);
  assertNonEmptyString(entityName, `${fieldBase}.name`, value.name);
  assertNonEmptyString(entityName, `${fieldBase}.type`, value.type);

  assertArray(entityName, `${fieldBase}.sessionTypes`, value.sessionTypes);
  assertRecord(entityName, `${fieldBase}.pointsTableBySessionType`, value.pointsTableBySessionType);

  assertRecord(entityName, `${fieldBase}.dropScorePolicy`, value.dropScorePolicy);
  assertNonEmptyString(entityName, `${fieldBase}.dropScorePolicy.strategy`, value.dropScorePolicy.strategy);
}

export class LeagueScoringConfigOrmMapper {
  constructor(private readonly championshipConfigMapper: ChampionshipConfigJsonMapper) {}

  toOrmEntity(domain: LeagueScoringConfig): LeagueScoringConfigOrmEntity {
    const entity = new LeagueScoringConfigOrmEntity();
    entity.id = domain.id.toString();
    entity.seasonId = domain.seasonId.toString();
    entity.scoringPresetId = domain.scoringPresetId ? domain.scoringPresetId.toString() : null;
    entity.championships = domain.championships.map((c) => this.championshipConfigMapper.toJson(c));
    return entity;
  }

  toDomain(entity: LeagueScoringConfigOrmEntity): LeagueScoringConfig {
    const entityName = 'LeagueScoringConfig';

    assertArray(entityName, 'championships', entity.championships);

    const championships = entity.championships.map((candidate, index) => {
      assertSerializedChampionshipConfig(candidate, index);
      return this.championshipConfigMapper.fromJson(candidate);
    });

    return LeagueScoringConfig.rehydrate({
      id: entity.id,
      seasonId: entity.seasonId,
      ...(entity.scoringPresetId ? { scoringPresetId: entity.scoringPresetId } : {}),
      championships,
    });
  }
}