/**
 * Data Factory for Integration Tests
 * Uses TypeORM repositories to create test data
 */

import { DataSource } from 'typeorm';
import { LeagueOrmEntity } from '../../../adapters/racing/persistence/typeorm/entities/LeagueOrmEntity';
import { SeasonOrmEntity } from '../../../adapters/racing/persistence/typeorm/entities/SeasonOrmEntity';
import { DriverOrmEntity } from '../../../adapters/racing/persistence/typeorm/entities/DriverOrmEntity';
import { RaceOrmEntity } from '../../../adapters/racing/persistence/typeorm/entities/RaceOrmEntity';
import { ResultOrmEntity } from '../../../adapters/racing/persistence/typeorm/entities/ResultOrmEntity';
import { LeagueOrmMapper } from '../../../adapters/racing/persistence/typeorm/mappers/LeagueOrmMapper';
import { SeasonOrmMapper } from '../../../adapters/racing/persistence/typeorm/mappers/SeasonOrmMapper';
import { RaceOrmMapper } from '../../../adapters/racing/persistence/typeorm/mappers/RaceOrmMapper';
import { ResultOrmMapper } from '../../../adapters/racing/persistence/typeorm/mappers/ResultOrmMapper';
import { TypeOrmLeagueRepository } from '../../../adapters/racing/persistence/typeorm/repositories/TypeOrmLeagueRepository';
import { TypeOrmSeasonRepository } from '../../../adapters/racing/persistence/typeorm/repositories/TypeOrmSeasonRepository';
import { TypeOrmRaceRepository } from '../../../adapters/racing/persistence/typeorm/repositories/TypeOrmRaceRepository';
import { TypeOrmResultRepository } from '../../../adapters/racing/persistence/typeorm/repositories/TypeOrmResultRepository';
import { TypeOrmDriverRepository } from '../../../adapters/racing/persistence/typeorm/repositories/TypeOrmDriverRepository';
import { League } from '../../../core/racing/domain/entities/League';
import { Season } from '../../../core/racing/domain/entities/season/Season';
import { Driver } from '../../../core/racing/domain/entities/Driver';
import { Race } from '../../../core/racing/domain/entities/Race';
import { Result } from '../../../core/racing/domain/entities/result/Result';
import { v4 as uuidv4 } from 'uuid';

export class DataFactory {
  private dataSource: DataSource;
  private leagueRepo: TypeOrmLeagueRepository;
  private seasonRepo: TypeOrmSeasonRepository;
  private driverRepo: TypeOrmDriverRepository;
  private raceRepo: TypeOrmRaceRepository;
  private resultRepo: TypeOrmResultRepository;

  constructor(private dbUrl: string) {
    this.dataSource = new DataSource({
      type: 'postgres',
      url: dbUrl,
      entities: [
        LeagueOrmEntity,
        SeasonOrmEntity,
        DriverOrmEntity,
        RaceOrmEntity,
        ResultOrmEntity,
      ],
      synchronize: false, // Don't sync, use existing schema
    });
  }

  async initialize(): Promise<void> {
    if (!this.dataSource.isInitialized) {
      await this.dataSource.initialize();
    }
    
    const leagueMapper = new LeagueOrmMapper();
    const seasonMapper = new SeasonOrmMapper();
    const raceMapper = new RaceOrmMapper();
    const resultMapper = new ResultOrmMapper();

    this.leagueRepo = new TypeOrmLeagueRepository(this.dataSource, leagueMapper);
    this.seasonRepo = new TypeOrmSeasonRepository(this.dataSource, seasonMapper);
    this.driverRepo = new TypeOrmDriverRepository(this.dataSource, leagueMapper); // Reuse mapper
    this.raceRepo = new TypeOrmRaceRepository(this.dataSource, raceMapper);
    this.resultRepo = new TypeOrmResultRepository(this.dataSource, resultMapper);
  }

  async cleanup(): Promise<void> {
    if (this.dataSource.isInitialized) {
      await this.dataSource.destroy();
    }
  }

  /**
   * Create a test league
   */
  async createLeague(overrides: Partial<{
    id: string;
    name: string;
    description: string;
    ownerId: string;
  }> = {}) {
    const league = League.create({
      id: overrides.id || uuidv4(),
      name: overrides.name || 'Test League',
      description: overrides.description || 'Integration Test League',
      ownerId: overrides.ownerId || uuidv4(),
      settings: {
        enableDriverChampionship: true,
        enableTeamChampionship: false,
        enableNationsChampionship: false,
        enableTrophyChampionship: false,
        visibility: 'unranked',
        maxDrivers: 32,
      },
      participantCount: 0,
    });

    await this.leagueRepo.create(league);
    return league;
  }

  /**
   * Create a test season
   */
  async createSeason(leagueId: string, overrides: Partial<{
    id: string;
    name: string;
    year: number;
    status: string;
  }> = {}) {
    const season = Season.create({
      id: overrides.id || uuidv4(),
      leagueId,
      gameId: 'iracing',
      name: overrides.name || 'Test Season',
      year: overrides.year || 2024,
      order: 1,
      status: overrides.status || 'active',
      startDate: new Date(),
      endDate: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
      schedulePublished: false,
    });

    await this.seasonRepo.create(season);
    return season;
  }

  /**
   * Create a test driver
   */
  async createDriver(overrides: Partial<{
    id: string;
    name: string;
    iracingId: string;
    country: string;
  }> = {}) {
    const driver = Driver.create({
      id: overrides.id || uuidv4(),
      iracingId: overrides.iracingId || `iracing-${uuidv4()}`,
      name: overrides.name || 'Test Driver',
      country: overrides.country || 'US',
    });

    // Need to insert directly since driver repo might not exist or be different
    await this.dataSource.getRepository(DriverOrmEntity).save({
      id: driver.id.toString(),
      iracingId: driver.iracingId,
      name: driver.name.toString(),
      country: driver.country,
      joinedAt: new Date(),
      bio: null,
      category: null,
      avatarRef: null,
    });

    return driver;
  }

  /**
   * Create a test race
   */
  async createRace(overrides: Partial<{
    id: string;
    leagueId: string;
    scheduledAt: Date;
    status: string;
    track: string;
    car: string;
  }> = {}) {
    const race = Race.create({
      id: overrides.id || uuidv4(),
      leagueId: overrides.leagueId || uuidv4(),
      scheduledAt: overrides.scheduledAt || new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
      track: overrides.track || 'Laguna Seca',
      car: overrides.car || 'Formula Ford',
      status: overrides.status || 'scheduled',
    });

    await this.raceRepo.create(race);
    return race;
  }

  /**
   * Create a test result
   */
  async createResult(raceId: string, driverId: string, overrides: Partial<{
    id: string;
    position: number;
    fastestLap: number;
    incidents: number;
    startPosition: number;
  }> = {}) {
    const result = Result.create({
      id: overrides.id || uuidv4(),
      raceId,
      driverId,
      position: overrides.position || 1,
      fastestLap: overrides.fastestLap || 0,
      incidents: overrides.incidents || 0,
      startPosition: overrides.startPosition || 1,
    });

    await this.resultRepo.create(result);
    return result;
  }

  /**
   * Create complete test scenario: league, season, drivers, races
   */
  async createTestScenario() {
    const league = await this.createLeague();
    const season = await this.createSeason(league.id.toString());
    const drivers = await Promise.all([
      this.createDriver({ name: 'Driver 1' }),
      this.createDriver({ name: 'Driver 2' }),
      this.createDriver({ name: 'Driver 3' }),
    ]);
    const races = await Promise.all([
      this.createRace({ 
        leagueId: league.id.toString(),
        name: 'Race 1',
        scheduledAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) 
      }),
      this.createRace({ 
        leagueId: league.id.toString(),
        name: 'Race 2',
        scheduledAt: new Date(Date.now() + 14 * 24 * 60 * 60 * 1000) 
      }),
    ]);

    return { league, season, drivers, races };
  }

  /**
   * Clean up specific entities
   */
  async deleteEntities(entities: { id: string | number }[], entityType: string) {
    const repository = this.dataSource.getRepository(entityType);
    for (const entity of entities) {
      await repository.delete(entity.id);
    }
  }
}