import type { Repository } from 'typeorm';

import type { Team } from '@core/racing/domain/entities/Team';
import type { TeamMembershipRepository } from '@core/racing/domain/repositories/TeamMembershipRepository';
import type { TeamRepository } from '@core/racing/domain/repositories/TeamRepository';
import type { TeamJoinRequest, TeamMembership } from '@core/racing/domain/types/TeamMembership';

import { TeamJoinRequestOrmEntity, TeamMembershipOrmEntity, TeamOrmEntity } from '../entities/TeamOrmEntities';
import { TeamMembershipOrmMapper, TeamOrmMapper } from '../mappers/TeamOrmMappers';

export class TypeOrmTeamRepository implements TeamRepository {
  constructor(
    private readonly repo: Repository<TeamOrmEntity>,
    private readonly mapper: TeamOrmMapper,
  ) {}

  async findById(id: string): Promise<Team | null> {
    // Validate UUID format to prevent database errors
    const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
    if (!uuidRegex.test(id)) {
      return null;
    }
    
    const entity = await this.repo.findOne({ where: { id } });
    return entity ? this.mapper.toDomain(entity) : null;
  }

  async findAll(): Promise<Team[]> {
    const entities = await this.repo.find();
    return entities.map((e) => this.mapper.toDomain(e));
  }

  async findByLeagueId(leagueId: string): Promise<Team[]> {
    const entities = await this.repo
      .createQueryBuilder('team')
      .where(':leagueId = ANY(team.leagues)', { leagueId })
      .getMany();

    return entities.map((e) => this.mapper.toDomain(e));
  }

  async create(team: Team): Promise<Team> {
    await this.repo.save(this.mapper.toOrmEntity(team));
    return team;
  }

  async update(team: Team): Promise<Team> {
    await this.repo.save(this.mapper.toOrmEntity(team));
    return team;
  }

  async delete(id: string): Promise<void> {
    await this.repo.delete({ id });
  }

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

export class TypeOrmTeamMembershipRepository implements TeamMembershipRepository {
  constructor(
    private readonly membershipRepo: Repository<TeamMembershipOrmEntity>,
    private readonly joinRequestRepo: Repository<TeamJoinRequestOrmEntity>,
    private readonly mapper: TeamMembershipOrmMapper,
  ) {}

  async getMembership(teamId: string, driverId: string): Promise<TeamMembership | null> {
    const entity = await this.membershipRepo.findOne({ where: { teamId, driverId } });
    return entity ? this.mapper.toDomainMembership(entity) : null;
  }

  async getActiveMembershipForDriver(driverId: string): Promise<TeamMembership | null> {
    const entity = await this.membershipRepo.findOne({ where: { driverId, status: 'active' } });
    return entity ? this.mapper.toDomainMembership(entity) : null;
  }

  async getTeamMembers(teamId: string): Promise<TeamMembership[]> {
    const entities = await this.membershipRepo.find({ where: { teamId, status: 'active' } });
    return entities.map((e) => this.mapper.toDomainMembership(e));
  }

  async saveMembership(membership: TeamMembership): Promise<TeamMembership> {
    await this.membershipRepo.save(this.mapper.toOrmMembership(membership));
    return membership;
  }

  async removeMembership(teamId: string, driverId: string): Promise<void> {
    await this.membershipRepo.delete({ teamId, driverId });
  }

  async countByTeamId(teamId: string): Promise<number> {
    return this.membershipRepo.count({ where: { teamId, status: 'active' } });
  }

  async getJoinRequests(teamId: string): Promise<TeamJoinRequest[]> {
    const entities = await this.joinRequestRepo.find({ where: { teamId } });
    return entities.map((e) => this.mapper.toDomainJoinRequest(e));
  }

  async saveJoinRequest(request: TeamJoinRequest): Promise<TeamJoinRequest> {
    await this.joinRequestRepo.save(this.mapper.toOrmJoinRequest(request));
    return request;
  }

  async removeJoinRequest(requestId: string): Promise<void> {
    await this.joinRequestRepo.delete({ id: requestId });
  }
}