import { Driver } from '@core/racing/domain/entities/Driver';
import { JoinRequest } from '@core/racing/domain/entities/JoinRequest';
import { League } from '@core/racing/domain/entities/League';
import { LeagueMembership } from '@core/racing/domain/entities/LeagueMembership';
import { Race } from '@core/racing/domain/entities/Race';
import { RaceRegistration } from '@core/racing/domain/entities/RaceRegistration';
import { Result as RaceResult } from '@core/racing/domain/entities/result/Result';
import { Season } from '@core/racing/domain/entities/season/Season';
import { SeasonSponsorship } from '@core/racing/domain/entities/season/SeasonSponsorship';
import { Sponsor } from '@core/racing/domain/entities/sponsor/Sponsor';
import { SponsorshipRequest } from '@core/racing/domain/entities/SponsorshipRequest';
import { Standing } from '@core/racing/domain/entities/Standing';
import { Team } from '@core/racing/domain/entities/Team';
import { Track } from '@core/racing/domain/entities/Track';
import type { TeamJoinRequest, TeamMembership } from '@core/racing/domain/types/TeamMembership';
import type { FeedItem } from '@core/social/domain/types/FeedItem';
import { RacingDriverFactory, type DriverStats } from './RacingDriverFactory';
import { RacingFeedFactory } from './RacingFeedFactory';
import { RacingFriendshipFactory } from './RacingFriendshipFactory';
import { RacingLeagueFactory } from './RacingLeagueFactory';
import { RacingLeagueWalletFactory } from './RacingLeagueWalletFactory';
import { RacingMembershipFactory } from './RacingMembershipFactory';
import { RacingRaceFactory } from './RacingRaceFactory';
import { RacingResultFactory } from './RacingResultFactory';
import { RacingSeasonSponsorshipFactory } from './RacingSeasonSponsorshipFactory';
import { RacingSponsorFactory } from './RacingSponsorFactory';
import { RacingStandingFactory } from './RacingStandingFactory';
import { RacingStewardingFactory } from './RacingStewardingFactory';
import { RacingTeamFactory, type TeamStats } from './RacingTeamFactory';
import { RacingTrackFactory } from './RacingTrackFactory';

export type Friendship = {
  driverId: string;
  friendId: string;
};

export type RacingSeed = {
  drivers: Driver[];
  driverStats: Map<string, DriverStats>;
  leagues: League[];
  seasons: Season[];
  seasonSponsorships: SeasonSponsorship[];
  sponsorshipRequests: SponsorshipRequest[];
  leagueWallets: import('@core/racing/domain/entities/league-wallet/LeagueWallet').LeagueWallet[];
  leagueWalletTransactions: import('@core/racing/domain/entities/league-wallet/Transaction').Transaction[];
  protests: import('@core/racing/domain/entities/Protest').Protest[];
  penalties: import('@core/racing/domain/entities/penalty/Penalty').Penalty[];
  races: Race[];
  results: RaceResult[];
  standings: Standing[];
  leagueMemberships: LeagueMembership[];
  leagueJoinRequests: JoinRequest[];
  raceRegistrations: RaceRegistration[];
  teams: Team[];
  teamStats: Map<string, TeamStats>;
  teamMemberships: TeamMembership[];
  teamJoinRequests: TeamJoinRequest[];
  sponsors: Sponsor[];
  tracks: Track[];
  friendships: Friendship[];
  feedEvents: FeedItem[];
};

export type RacingSeedOptions = {
  driverCount?: number;
  baseDate?: Date;
  persistence?: 'postgres' | 'inmemory';
};

export const racingSeedDefaults: Readonly<
  Omit<Required<RacingSeedOptions>, 'baseDate'> & { baseDate: () => Date }
> = {
  driverCount: 150, // Increased from 100 to 150
  baseDate: () => new Date(),
  persistence: 'inmemory',
};

class RacingSeedFactory {
  private readonly driverCount: number;
  private readonly baseDate: Date;
  private readonly persistence: 'postgres' | 'inmemory';

  constructor(options: RacingSeedOptions) {
    this.driverCount = options.driverCount ?? racingSeedDefaults.driverCount;
    this.baseDate = options.baseDate ?? racingSeedDefaults.baseDate();
    this.persistence = options.persistence ?? racingSeedDefaults.persistence;
  }

  create(): RacingSeed {
    const driverFactory = new RacingDriverFactory(this.driverCount, this.baseDate, this.persistence);
    const trackFactory = new RacingTrackFactory();
    const raceFactory = new RacingRaceFactory(this.baseDate, this.persistence);
    const resultFactory = new RacingResultFactory(this.persistence);
    const standingFactory = new RacingStandingFactory();
    const membershipFactory = new RacingMembershipFactory(this.baseDate, this.persistence);
    const sponsorFactory = new RacingSponsorFactory(this.baseDate, this.persistence);
    const seasonSponsorshipFactory = new RacingSeasonSponsorshipFactory(this.baseDate, this.persistence);
    const leagueWalletFactory = new RacingLeagueWalletFactory(this.baseDate, this.persistence);
    const friendshipFactory = new RacingFriendshipFactory();
    const feedFactory = new RacingFeedFactory(this.baseDate, this.persistence);

    const drivers = driverFactory.create();
    const driverStats = driverFactory.generateDriverStats(drivers);
    const tracks = trackFactory.create();
    const leagueFactory = new RacingLeagueFactory(this.baseDate, drivers, this.persistence);
    const leagues = leagueFactory.create();
    const sponsors = sponsorFactory.create();
    const seasons = seasonSponsorshipFactory.createSeasons(leagues);
    const seasonSponsorships = seasonSponsorshipFactory.createSeasonSponsorships(seasons, sponsors);
    const sponsorshipRequests = seasonSponsorshipFactory.createSponsorshipRequests(seasons, sponsors);

    const leagueMemberships = membershipFactory.createLeagueMemberships(drivers, leagues);
    const leagueJoinRequests = membershipFactory.createLeagueJoinRequests(drivers, leagues, leagueMemberships);

    const { wallets: leagueWallets, transactions: leagueWalletTransactions } = leagueWalletFactory.create(leagues);

    const teamFactory = new RacingTeamFactory(this.baseDate, this.persistence);
    const teams = teamFactory.createTeams(drivers, leagues);
    const teamStats = teamFactory.generateTeamStats(teams);
    const races = raceFactory.create(leagues, tracks);
    const results = resultFactory.create(drivers, races);
    const standings = standingFactory.create(leagues, races, results);
    const raceRegistrations = membershipFactory.createRaceRegistrations(races, drivers, leagueMemberships);
    const teamMemberships = teamFactory.createTeamMemberships(drivers, teams);
    const teamJoinRequests = teamFactory.createTeamJoinRequests(drivers, teams, teamMemberships);

    const stewardingFactory = new RacingStewardingFactory(this.baseDate, this.persistence);
    const { protests, penalties } = stewardingFactory.create(races, drivers, leagueMemberships);

    const friendships = friendshipFactory.create(drivers);
    const feedEvents = feedFactory.create(drivers, friendships, races, leagues);

    return {
      drivers,
      driverStats,
      leagues,
      seasons,
      seasonSponsorships,
      sponsorshipRequests,
      leagueWallets,
      leagueWalletTransactions,
      protests,
      penalties,
      races,
      results,
      standings,
      leagueMemberships,
      leagueJoinRequests,
      raceRegistrations,
      teams,
      teamStats,
      teamMemberships,
      teamJoinRequests,
      sponsors,
      tracks,
      friendships,
      feedEvents,
    };
  }
}

export function createRacingSeed(options: RacingSeedOptions = {}): RacingSeed {
  return new RacingSeedFactory(options).create();
}