import { Module } from '@nestjs/common';
import { TypeOrmModule, getDataSourceToken, getRepositoryToken } from '@nestjs/typeorm';
import type { DataSource, Repository } from 'typeorm';

import { LoggingModule } from '../../domain/logging/LoggingModule';

import {
  DRIVER_REPOSITORY_TOKEN,
  GAME_REPOSITORY_TOKEN,
  LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN,
  LEAGUE_REPOSITORY_TOKEN,
  LEAGUE_SCORING_CONFIG_REPOSITORY_TOKEN,
  LEAGUE_WALLET_REPOSITORY_TOKEN,
  PENALTY_REPOSITORY_TOKEN,
  PROTEST_REPOSITORY_TOKEN,
  RACE_REGISTRATION_REPOSITORY_TOKEN,
  RACE_REPOSITORY_TOKEN,
  RESULT_REPOSITORY_TOKEN,
  SEASON_REPOSITORY_TOKEN,
  SEASON_SPONSORSHIP_REPOSITORY_TOKEN,
  SPONSOR_REPOSITORY_TOKEN,
  SPONSORSHIP_PRICING_REPOSITORY_TOKEN,
  SPONSORSHIP_REQUEST_REPOSITORY_TOKEN,
  STANDING_REPOSITORY_TOKEN,
  TEAM_MEMBERSHIP_REPOSITORY_TOKEN,
  TEAM_REPOSITORY_TOKEN,
  TRANSACTION_REPOSITORY_TOKEN,
  DRIVER_STATS_REPOSITORY_TOKEN,
  TEAM_STATS_REPOSITORY_TOKEN,
  MEDIA_REPOSITORY_TOKEN,
} from '../inmemory/InMemoryRacingPersistenceModule';

import { DriverOrmEntity } from '@adapters/racing/persistence/typeorm/entities/DriverOrmEntity';
import { LeagueMembershipOrmEntity } from '@adapters/racing/persistence/typeorm/entities/LeagueMembershipOrmEntity';
import { LeagueOrmEntity } from '@adapters/racing/persistence/typeorm/entities/LeagueOrmEntity';
import { LeagueScoringConfigOrmEntity } from '@adapters/racing/persistence/typeorm/entities/LeagueScoringConfigOrmEntity';
import { RaceOrmEntity } from '@adapters/racing/persistence/typeorm/entities/RaceOrmEntity';
import { RaceRegistrationOrmEntity } from '@adapters/racing/persistence/typeorm/entities/RaceRegistrationOrmEntity';
import { SeasonOrmEntity } from '@adapters/racing/persistence/typeorm/entities/SeasonOrmEntity';
import { ResultOrmEntity } from '@adapters/racing/persistence/typeorm/entities/ResultOrmEntity';
import { StandingOrmEntity } from '@adapters/racing/persistence/typeorm/entities/StandingOrmEntity';
import {
  GameOrmEntity,
  LeagueWalletOrmEntity,
  PenaltyOrmEntity,
  ProtestOrmEntity,
  SeasonSponsorshipOrmEntity,
  SponsorOrmEntity,
  SponsorshipPricingOrmEntity,
  SponsorshipRequestOrmEntity,
  TransactionOrmEntity,
} from '@adapters/racing/persistence/typeorm/entities/MissingRacingOrmEntities';
import {
  TeamJoinRequestOrmEntity,
  TeamMembershipOrmEntity,
  TeamOrmEntity,
} from '@adapters/racing/persistence/typeorm/entities/TeamOrmEntities';
import { TeamStatsOrmEntity } from '@adapters/racing/persistence/typeorm/entities/TeamStatsOrmEntity';

import { TypeOrmDriverRepository } from '@adapters/racing/persistence/typeorm/repositories/TypeOrmDriverRepository';
import { TypeOrmLeagueMembershipRepository } from '@adapters/racing/persistence/typeorm/repositories/TypeOrmLeagueMembershipRepository';
import { TypeOrmLeagueRepository } from '@adapters/racing/persistence/typeorm/repositories/TypeOrmLeagueRepository';
import { TypeOrmLeagueScoringConfigRepository } from '@adapters/racing/persistence/typeorm/repositories/TypeOrmLeagueScoringConfigRepository';
import { TypeOrmRaceRegistrationRepository } from '@adapters/racing/persistence/typeorm/repositories/TypeOrmRaceRegistrationRepository';
import { TypeOrmRaceRepository } from '@adapters/racing/persistence/typeorm/repositories/TypeOrmRaceRepository';
import { TypeOrmSeasonRepository } from '@adapters/racing/persistence/typeorm/repositories/TypeOrmSeasonRepository';
import { TypeOrmResultRepository } from '@adapters/racing/persistence/typeorm/repositories/TypeOrmResultRepository';
import { TypeOrmStandingRepository } from '@adapters/racing/persistence/typeorm/repositories/TypeOrmStandingRepository';
import {
  TypeOrmGameRepository,
  TypeOrmLeagueWalletRepository,
  TypeOrmSeasonSponsorshipRepository,
  TypeOrmSponsorRepository,
  TypeOrmSponsorshipPricingRepository,
  TypeOrmSponsorshipRequestRepository,
  TypeOrmTransactionRepository,
} from '@adapters/racing/persistence/typeorm/repositories/CommerceTypeOrmRepositories';
import { TypeOrmPenaltyRepository, TypeOrmProtestRepository } from '@adapters/racing/persistence/typeorm/repositories/StewardingTypeOrmRepositories';
import { TypeOrmTeamMembershipRepository, TypeOrmTeamRepository } from '@adapters/racing/persistence/typeorm/repositories/TeamTypeOrmRepositories';

// Import in-memory implementations for new repositories (TypeORM versions not yet implemented)
import { InMemoryDriverStatsRepository } from '@adapters/racing/persistence/inmemory/InMemoryDriverStatsRepository';
import { InMemoryMediaRepository } from '@adapters/racing/persistence/media/InMemoryMediaRepository';

// Import TypeORM repository for team stats
import { TypeOrmTeamStatsRepository } from '@adapters/racing/persistence/typeorm/repositories/TypeOrmTeamStatsRepository';

import { DriverOrmMapper } from '@adapters/racing/persistence/typeorm/mappers/DriverOrmMapper';
import { LeagueMembershipOrmMapper } from '@adapters/racing/persistence/typeorm/mappers/LeagueMembershipOrmMapper';
import { LeagueOrmMapper } from '@adapters/racing/persistence/typeorm/mappers/LeagueOrmMapper';
import { RaceRegistrationOrmMapper } from '@adapters/racing/persistence/typeorm/mappers/RaceRegistrationOrmMapper';
import { RaceOrmMapper } from '@adapters/racing/persistence/typeorm/mappers/RaceOrmMapper';
import { SeasonOrmMapper } from '@adapters/racing/persistence/typeorm/mappers/SeasonOrmMapper';
import { ResultOrmMapper } from '@adapters/racing/persistence/typeorm/mappers/ResultOrmMapper';
import { StandingOrmMapper } from '@adapters/racing/persistence/typeorm/mappers/StandingOrmMapper';
import { PointsTableJsonMapper } from '@adapters/racing/persistence/typeorm/mappers/PointsTableJsonMapper';
import { ChampionshipConfigJsonMapper } from '@adapters/racing/persistence/typeorm/mappers/ChampionshipConfigJsonMapper';
import { LeagueScoringConfigOrmMapper } from '@adapters/racing/persistence/typeorm/mappers/LeagueScoringConfigOrmMapper';
import {
  GameOrmMapper,
  LeagueWalletOrmMapper,
  SeasonSponsorshipOrmMapper,
  SponsorOrmMapper,
  SponsorshipPricingOrmMapper,
  SponsorshipRequestOrmMapper,
  TransactionOrmMapper,
} from '@adapters/racing/persistence/typeorm/mappers/CommerceOrmMappers';
import { MoneyOrmMapper } from '@adapters/racing/persistence/typeorm/mappers/MoneyOrmMapper';
import { PenaltyOrmMapper, ProtestOrmMapper } from '@adapters/racing/persistence/typeorm/mappers/StewardingOrmMappers';
import { TeamMembershipOrmMapper, TeamOrmMapper } from '@adapters/racing/persistence/typeorm/mappers/TeamOrmMappers';
import { TeamStatsOrmMapper } from '@adapters/racing/persistence/typeorm/mappers/TeamStatsOrmMapper';

import { getPointsSystems } from '@adapters/bootstrap/PointsSystems';
import type { Logger } from '@core/shared/application/Logger';

const RACING_POINTS_SYSTEMS_TOKEN = 'RACING_POINTS_SYSTEMS_TOKEN';

const typeOrmFeatureImports = [
  TypeOrmModule.forFeature([
    DriverOrmEntity,
    LeagueMembershipOrmEntity,
    LeagueOrmEntity,
    SeasonOrmEntity,
    RaceOrmEntity,
    RaceRegistrationOrmEntity,
    LeagueScoringConfigOrmEntity,
    ResultOrmEntity,
    StandingOrmEntity,

    TeamOrmEntity,
    TeamMembershipOrmEntity,
    TeamJoinRequestOrmEntity,
    TeamStatsOrmEntity,

    PenaltyOrmEntity,
    ProtestOrmEntity,

    GameOrmEntity,
    LeagueWalletOrmEntity,
    TransactionOrmEntity,

    SponsorOrmEntity,
    SponsorshipPricingOrmEntity,
    SponsorshipRequestOrmEntity,
    SeasonSponsorshipOrmEntity,
  ]),
];

@Module({
  imports: [LoggingModule, ...typeOrmFeatureImports],
  providers: [
    { provide: DriverOrmMapper, useFactory: () => new DriverOrmMapper() },
    { provide: LeagueMembershipOrmMapper, useFactory: () => new LeagueMembershipOrmMapper() },
    { provide: RaceRegistrationOrmMapper, useFactory: () => new RaceRegistrationOrmMapper() },
    { provide: ResultOrmMapper, useFactory: () => new ResultOrmMapper() },
    { provide: StandingOrmMapper, useFactory: () => new StandingOrmMapper() },
    { provide: LeagueOrmMapper, useFactory: () => new LeagueOrmMapper() },
    { provide: RaceOrmMapper, useFactory: () => new RaceOrmMapper() },
    { provide: SeasonOrmMapper, useFactory: () => new SeasonOrmMapper() },

    { provide: TeamOrmMapper, useFactory: () => new TeamOrmMapper() },
    { provide: TeamMembershipOrmMapper, useFactory: () => new TeamMembershipOrmMapper() },
    { provide: TeamStatsOrmMapper, useFactory: () => new TeamStatsOrmMapper() },

    { provide: PenaltyOrmMapper, useFactory: () => new PenaltyOrmMapper() },
    { provide: ProtestOrmMapper, useFactory: () => new ProtestOrmMapper() },

    { provide: MoneyOrmMapper, useFactory: () => new MoneyOrmMapper() },
    { provide: GameOrmMapper, useFactory: () => new GameOrmMapper() },
    { provide: SponsorOrmMapper, useFactory: () => new SponsorOrmMapper() },
    {
      provide: LeagueWalletOrmMapper,
      useFactory: (moneyMapper: MoneyOrmMapper) => new LeagueWalletOrmMapper(moneyMapper),
      inject: [MoneyOrmMapper],
    },
    {
      provide: TransactionOrmMapper,
      useFactory: (moneyMapper: MoneyOrmMapper) => new TransactionOrmMapper(moneyMapper),
      inject: [MoneyOrmMapper],
    },
    {
      provide: SponsorshipPricingOrmMapper,
      useFactory: (moneyMapper: MoneyOrmMapper) => new SponsorshipPricingOrmMapper(moneyMapper),
      inject: [MoneyOrmMapper],
    },
    {
      provide: SponsorshipRequestOrmMapper,
      useFactory: (moneyMapper: MoneyOrmMapper) => new SponsorshipRequestOrmMapper(moneyMapper),
      inject: [MoneyOrmMapper],
    },
    {
      provide: SeasonSponsorshipOrmMapper,
      useFactory: (moneyMapper: MoneyOrmMapper) => new SeasonSponsorshipOrmMapper(moneyMapper),
      inject: [MoneyOrmMapper],
    },

    { provide: RACING_POINTS_SYSTEMS_TOKEN, useFactory: () => getPointsSystems() },
    {
      provide: DRIVER_REPOSITORY_TOKEN,
      useFactory: (dataSource: DataSource, mapper: DriverOrmMapper) => new TypeOrmDriverRepository(dataSource, mapper),
      inject: [getDataSourceToken(), DriverOrmMapper],
    },
    {
      provide: LEAGUE_REPOSITORY_TOKEN,
      useFactory: (dataSource: DataSource, mapper: LeagueOrmMapper) => new TypeOrmLeagueRepository(dataSource, mapper),
      inject: [getDataSourceToken(), LeagueOrmMapper],
    },
    {
      provide: RACE_REPOSITORY_TOKEN,
      useFactory: (dataSource: DataSource, mapper: RaceOrmMapper) => new TypeOrmRaceRepository(dataSource, mapper),
      inject: [getDataSourceToken(), RaceOrmMapper],
    },
    {
      provide: RESULT_REPOSITORY_TOKEN,
      useFactory: (dataSource: DataSource, mapper: ResultOrmMapper) => new TypeOrmResultRepository(dataSource, mapper),
      inject: [getDataSourceToken(), ResultOrmMapper],
    },
    {
      provide: STANDING_REPOSITORY_TOKEN,
      useFactory: (
        dataSource: DataSource,
        standingMapper: StandingOrmMapper,
        resultMapper: ResultOrmMapper,
        leagueMapper: LeagueOrmMapper,
        pointsSystems: Record<string, Record<number, number>>,
      ) => new TypeOrmStandingRepository(dataSource, standingMapper, resultMapper, leagueMapper, pointsSystems),
      inject: [getDataSourceToken(), StandingOrmMapper, ResultOrmMapper, LeagueOrmMapper, RACING_POINTS_SYSTEMS_TOKEN],
    },
    {
      provide: LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN,
      useFactory: (dataSource: DataSource, mapper: LeagueMembershipOrmMapper) =>
        new TypeOrmLeagueMembershipRepository(dataSource, mapper),
      inject: [getDataSourceToken(), LeagueMembershipOrmMapper],
    },
    {
      provide: RACE_REGISTRATION_REPOSITORY_TOKEN,
      useFactory: (dataSource: DataSource, mapper: RaceRegistrationOrmMapper) =>
        new TypeOrmRaceRegistrationRepository(dataSource, mapper),
      inject: [getDataSourceToken(), RaceRegistrationOrmMapper],
    },
    {
      provide: TEAM_REPOSITORY_TOKEN,
      useFactory: (repo: Repository<TeamOrmEntity>, mapper: TeamOrmMapper) => new TypeOrmTeamRepository(repo, mapper),
      inject: [getRepositoryToken(TeamOrmEntity), TeamOrmMapper],
    },
    {
      provide: TEAM_MEMBERSHIP_REPOSITORY_TOKEN,
      useFactory: (
        membershipRepo: Repository<TeamMembershipOrmEntity>,
        joinRequestRepo: Repository<TeamJoinRequestOrmEntity>,
        mapper: TeamMembershipOrmMapper,
      ) => new TypeOrmTeamMembershipRepository(membershipRepo, joinRequestRepo, mapper),
      inject: [
        getRepositoryToken(TeamMembershipOrmEntity),
        getRepositoryToken(TeamJoinRequestOrmEntity),
        TeamMembershipOrmMapper,
      ],
    },
    {
      provide: PENALTY_REPOSITORY_TOKEN,
      useFactory: (repo: Repository<PenaltyOrmEntity>, mapper: PenaltyOrmMapper) => new TypeOrmPenaltyRepository(repo, mapper),
      inject: [getRepositoryToken(PenaltyOrmEntity), PenaltyOrmMapper],
    },
    {
      provide: PROTEST_REPOSITORY_TOKEN,
      useFactory: (repo: Repository<ProtestOrmEntity>, mapper: ProtestOrmMapper) => new TypeOrmProtestRepository(repo, mapper),
      inject: [getRepositoryToken(ProtestOrmEntity), ProtestOrmMapper],
    },
    {
      provide: SEASON_REPOSITORY_TOKEN,
      useFactory: (dataSource: DataSource, mapper: SeasonOrmMapper) => new TypeOrmSeasonRepository(dataSource, mapper),
      inject: [getDataSourceToken(), SeasonOrmMapper],
    },
    {
      provide: SEASON_SPONSORSHIP_REPOSITORY_TOKEN,
      useFactory: (repo: Repository<SeasonSponsorshipOrmEntity>, mapper: SeasonSponsorshipOrmMapper) =>
        new TypeOrmSeasonSponsorshipRepository(repo, mapper),
      inject: [getRepositoryToken(SeasonSponsorshipOrmEntity), SeasonSponsorshipOrmMapper],
    },
    {
      provide: LEAGUE_SCORING_CONFIG_REPOSITORY_TOKEN,
      useFactory: (dataSource: DataSource) => {
        const pointsTableMapper = new PointsTableJsonMapper();
        const championshipMapper = new ChampionshipConfigJsonMapper(pointsTableMapper);
        const scoringConfigMapper = new LeagueScoringConfigOrmMapper(championshipMapper);
        return new TypeOrmLeagueScoringConfigRepository(dataSource, scoringConfigMapper);
      },
      inject: [getDataSourceToken()],
    },
    {
      provide: GAME_REPOSITORY_TOKEN,
      useFactory: (repo: Repository<GameOrmEntity>, mapper: GameOrmMapper) => new TypeOrmGameRepository(repo, mapper),
      inject: [getRepositoryToken(GameOrmEntity), GameOrmMapper],
    },
    {
      provide: LEAGUE_WALLET_REPOSITORY_TOKEN,
      useFactory: (repo: Repository<LeagueWalletOrmEntity>, mapper: LeagueWalletOrmMapper) =>
        new TypeOrmLeagueWalletRepository(repo, mapper),
      inject: [getRepositoryToken(LeagueWalletOrmEntity), LeagueWalletOrmMapper],
    },
    {
      provide: TRANSACTION_REPOSITORY_TOKEN,
      useFactory: (repo: Repository<TransactionOrmEntity>, mapper: TransactionOrmMapper) => new TypeOrmTransactionRepository(repo, mapper),
      inject: [getRepositoryToken(TransactionOrmEntity), TransactionOrmMapper],
    },
    {
      provide: SPONSOR_REPOSITORY_TOKEN,
      useFactory: (repo: Repository<SponsorOrmEntity>, mapper: SponsorOrmMapper) => new TypeOrmSponsorRepository(repo, mapper),
      inject: [getRepositoryToken(SponsorOrmEntity), SponsorOrmMapper],
    },
    {
      provide: SPONSORSHIP_PRICING_REPOSITORY_TOKEN,
      useFactory: (repo: Repository<SponsorshipPricingOrmEntity>, mapper: SponsorshipPricingOrmMapper) =>
        new TypeOrmSponsorshipPricingRepository(repo, mapper),
      inject: [getRepositoryToken(SponsorshipPricingOrmEntity), SponsorshipPricingOrmMapper],
    },
    {
      provide: SPONSORSHIP_REQUEST_REPOSITORY_TOKEN,
      useFactory: (repo: Repository<SponsorshipRequestOrmEntity>, mapper: SponsorshipRequestOrmMapper) =>
        new TypeOrmSponsorshipRequestRepository(repo, mapper),
      inject: [getRepositoryToken(SponsorshipRequestOrmEntity), SponsorshipRequestOrmMapper],
    },
    {
      provide: DRIVER_STATS_REPOSITORY_TOKEN,
      useFactory: (logger: Logger) => new InMemoryDriverStatsRepository(logger),
      inject: ['Logger'],
    },
    {
      provide: TEAM_STATS_REPOSITORY_TOKEN,
      useFactory: (repo: Repository<TeamStatsOrmEntity>, mapper: TeamStatsOrmMapper) => new TypeOrmTeamStatsRepository(repo, mapper),
      inject: [getRepositoryToken(TeamStatsOrmEntity), TeamStatsOrmMapper],
    },
    {
      provide: MEDIA_REPOSITORY_TOKEN,
      useFactory: (logger: Logger) => new InMemoryMediaRepository(logger),
      inject: ['Logger'],
    },
  ],
  exports: [
    DRIVER_REPOSITORY_TOKEN,
    LEAGUE_REPOSITORY_TOKEN,
    RACE_REPOSITORY_TOKEN,
    RESULT_REPOSITORY_TOKEN,
    STANDING_REPOSITORY_TOKEN,
    LEAGUE_MEMBERSHIP_REPOSITORY_TOKEN,
    RACE_REGISTRATION_REPOSITORY_TOKEN,
    TEAM_REPOSITORY_TOKEN,
    TEAM_MEMBERSHIP_REPOSITORY_TOKEN,
    PENALTY_REPOSITORY_TOKEN,
    PROTEST_REPOSITORY_TOKEN,
    SEASON_REPOSITORY_TOKEN,
    SEASON_SPONSORSHIP_REPOSITORY_TOKEN,
    LEAGUE_SCORING_CONFIG_REPOSITORY_TOKEN,
    GAME_REPOSITORY_TOKEN,
    LEAGUE_WALLET_REPOSITORY_TOKEN,
    TRANSACTION_REPOSITORY_TOKEN,
    SPONSOR_REPOSITORY_TOKEN,
    SPONSORSHIP_PRICING_REPOSITORY_TOKEN,
    SPONSORSHIP_REQUEST_REPOSITORY_TOKEN,
    DRIVER_STATS_REPOSITORY_TOKEN,
    TEAM_STATS_REPOSITORY_TOKEN,
    MEDIA_REPOSITORY_TOKEN,
  ],
})
export class PostgresRacingPersistenceModule {}
