import type { Repository } from 'typeorm';

import type { IPenaltyRepository } from '@core/racing/domain/repositories/IPenaltyRepository';
import type { IProtestRepository } from '@core/racing/domain/repositories/IProtestRepository';
import type { Penalty } from '@core/racing/domain/entities/penalty/Penalty';
import type { Protest } from '@core/racing/domain/entities/Protest';

import { PenaltyOrmEntity, ProtestOrmEntity } from '../entities/MissingRacingOrmEntities';
import { PenaltyOrmMapper, ProtestOrmMapper } from '../mappers/StewardingOrmMappers';

export class TypeOrmPenaltyRepository implements IPenaltyRepository {
  constructor(
    private readonly repo: Repository<PenaltyOrmEntity>,
    private readonly mapper: PenaltyOrmMapper,
  ) {}

  async findById(id: string): Promise<Penalty | null> {
    const entity = await this.repo.findOne({ where: { id } });
    return entity ? this.mapper.toDomain(entity) : null;
  }

  async findByRaceId(raceId: string): Promise<Penalty[]> {
    const entities = await this.repo.find({ where: { raceId } });
    return entities.map((e) => this.mapper.toDomain(e));
  }

  async findByDriverId(driverId: string): Promise<Penalty[]> {
    const entities = await this.repo.find({ where: { driverId } });
    return entities.map((e) => this.mapper.toDomain(e));
  }

  async findByProtestId(protestId: string): Promise<Penalty[]> {
    const entities = await this.repo.find({ where: { protestId } });
    return entities.map((e) => this.mapper.toDomain(e));
  }

  async findPending(): Promise<Penalty[]> {
    const entities = await this.repo.find({ where: { status: 'pending' } });
    return entities.map((e) => this.mapper.toDomain(e));
  }

  async findIssuedBy(stewardId: string): Promise<Penalty[]> {
    const entities = await this.repo.find({ where: { issuedBy: stewardId } });
    return entities.map((e) => this.mapper.toDomain(e));
  }

  async create(penalty: Penalty): Promise<void> {
    await this.repo.save(this.mapper.toOrmEntity(penalty));
  }

  async update(penalty: Penalty): Promise<void> {
    await this.repo.save(this.mapper.toOrmEntity(penalty));
  }

  async exists(id: string): Promise<boolean> {
    const count = await this.repo.count({ where: { id } });
    return count > 0;
  }
}

export class TypeOrmProtestRepository implements IProtestRepository {
  constructor(
    private readonly repo: Repository<ProtestOrmEntity>,
    private readonly mapper: ProtestOrmMapper,
  ) {}

  async findById(id: string): Promise<Protest | null> {
    const entity = await this.repo.findOne({ where: { id } });
    return entity ? this.mapper.toDomain(entity) : null;
  }

  async findByRaceId(raceId: string): Promise<Protest[]> {
    const entities = await this.repo.find({ where: { raceId } });
    return entities.map((e) => this.mapper.toDomain(e));
  }

  async findByProtestingDriverId(driverId: string): Promise<Protest[]> {
    const entities = await this.repo.find({ where: { protestingDriverId: driverId } });
    return entities.map((e) => this.mapper.toDomain(e));
  }

  async findByAccusedDriverId(driverId: string): Promise<Protest[]> {
    const entities = await this.repo.find({ where: { accusedDriverId: driverId } });
    return entities.map((e) => this.mapper.toDomain(e));
  }

  async findPending(): Promise<Protest[]> {
    const entities = await this.repo.find({ where: { status: 'pending' } });
    return entities.map((e) => this.mapper.toDomain(e));
  }

  async findUnderReviewBy(stewardId: string): Promise<Protest[]> {
    const entities = await this.repo.find({ where: { reviewedBy: stewardId, status: 'under_review' } });
    return entities.map((e) => this.mapper.toDomain(e));
  }

  async create(protest: Protest): Promise<void> {
    await this.repo.save(this.mapper.toOrmEntity(protest));
  }

  async update(protest: Protest): Promise<void> {
    await this.repo.save(this.mapper.toOrmEntity(protest));
  }

  async exists(id: string): Promise<boolean> {
    const count = await this.repo.count({ where: { id } });
    return count > 0;
  }
}