import type { BonusRule } from '@core/racing/domain/types/BonusRule';
import type { ChampionshipConfig } from '@core/racing/domain/types/ChampionshipConfig';
import type { DropScorePolicy } from '@core/racing/domain/types/DropScorePolicy';
import type { SessionType } from '@core/racing/domain/types/SessionType';
import { PointsTableJsonMapper, type SerializedPointsTable } from './PointsTableJsonMapper';

export type SerializedChampionshipConfig = {
  id: string;
  name: string;
  type: ChampionshipConfig['type'];
  sessionTypes: SessionType[];
  pointsTableBySessionType: Record<SessionType, SerializedPointsTable>;
  bonusRulesBySessionType?: Record<SessionType, BonusRule[]>;
  dropScorePolicy: DropScorePolicy;
};

export class ChampionshipConfigJsonMapper {
  constructor(private readonly pointsTableMapper: PointsTableJsonMapper) {}

  toJson(config: ChampionshipConfig): SerializedChampionshipConfig {
    const pointsTableBySessionType = {} as Record<SessionType, SerializedPointsTable>;

    for (const [sessionType, pointsTable] of Object.entries(config.pointsTableBySessionType) as Array<
      [SessionType, Parameters<PointsTableJsonMapper['toJson']>[0]]
    >) {
      pointsTableBySessionType[sessionType] = this.pointsTableMapper.toJson(pointsTable);
    }

    return {
      id: config.id,
      name: config.name,
      type: config.type,
      sessionTypes: config.sessionTypes,
      pointsTableBySessionType,
      ...(config.bonusRulesBySessionType ? { bonusRulesBySessionType: config.bonusRulesBySessionType } : {}),
      dropScorePolicy: config.dropScorePolicy,
    };
  }

  fromJson(serialized: SerializedChampionshipConfig): ChampionshipConfig {
    const pointsTableBySessionType = {} as ChampionshipConfig['pointsTableBySessionType'];

    for (const [sessionType, pointsTable] of Object.entries(serialized.pointsTableBySessionType) as Array<
      [SessionType, SerializedPointsTable]
    >) {
      pointsTableBySessionType[sessionType] = this.pointsTableMapper.fromJson(pointsTable);
    }

    return {
      id: serialized.id,
      name: serialized.name,
      type: serialized.type,
      sessionTypes: serialized.sessionTypes,
      pointsTableBySessionType,
      ...(serialized.bonusRulesBySessionType ? { bonusRulesBySessionType: serialized.bonusRulesBySessionType } : {}),
      dropScorePolicy: serialized.dropScorePolicy,
    };
  }
}