/**
 * Application Layer: Entity to DTO Mappers
 * 
 * Transforms domain entities to plain objects for crossing architectural boundaries.
 * These mappers handle the Server Component -> Client Component boundary in Next.js 15.
 */

import { Driver } from '../../domain/entities/Driver';
import { League } from '../../domain/entities/League';
import { Race } from '../../domain/entities/Race';
import { Result } from '../../domain/entities/Result';
import { Standing } from '../../domain/entities/Standing';
import type { DriverDTO } from '../dto/DriverDTO';
import type { LeagueDTO } from '../dto/LeagueDTO';
import type { RaceDTO } from '../dto/RaceDTO';
import type { ResultDTO } from '../dto/ResultDTO';
import type { StandingDTO } from '../dto/StandingDTO';

export class EntityMappers {
  static toDriverDTO(driver: Driver | null): DriverDTO | null {
    if (!driver) return null;
    return {
      id: driver.id,
      iracingId: driver.iracingId,
      name: driver.name,
      country: driver.country,
      bio: driver.bio ?? '',
      joinedAt: driver.joinedAt.toISOString(),
    };
  }

  static toLeagueDTO(league: League | null): LeagueDTO | null {
    if (!league) return null;

    const socialLinks =
      league.socialLinks !== undefined
        ? {
            ...(league.socialLinks.discordUrl !== undefined
              ? { discordUrl: league.socialLinks.discordUrl }
              : {}),
            ...(league.socialLinks.youtubeUrl !== undefined
              ? { youtubeUrl: league.socialLinks.youtubeUrl }
              : {}),
            ...(league.socialLinks.websiteUrl !== undefined
              ? { websiteUrl: league.socialLinks.websiteUrl }
              : {}),
          }
        : undefined;

    return {
      id: league.id,
      name: league.name,
      description: league.description,
      ownerId: league.ownerId,
      settings: league.settings,
      createdAt: league.createdAt.toISOString(),
      ...(socialLinks !== undefined ? { socialLinks } : {}),
    };
  }

  static toLeagueDTOs(leagues: League[]): LeagueDTO[] {
    return leagues.map((league) => {
      const socialLinks =
        league.socialLinks !== undefined
          ? {
              ...(league.socialLinks.discordUrl !== undefined
                ? { discordUrl: league.socialLinks.discordUrl }
                : {}),
              ...(league.socialLinks.youtubeUrl !== undefined
                ? { youtubeUrl: league.socialLinks.youtubeUrl }
                : {}),
              ...(league.socialLinks.websiteUrl !== undefined
                ? { websiteUrl: league.socialLinks.websiteUrl }
                : {}),
            }
          : undefined;

      return {
        id: league.id,
        name: league.name,
        description: league.description,
        ownerId: league.ownerId,
        settings: league.settings,
        createdAt: league.createdAt.toISOString(),
        ...(socialLinks !== undefined ? { socialLinks } : {}),
      };
    });
  }

  static toRaceDTO(race: Race | null): RaceDTO | null {
    if (!race) return null;

    const sessionTypeMap = {
      practice: 'practice' as const,
      qualifying: 'qualifying' as const,
      q1: 'qualifying' as const,
      q2: 'qualifying' as const,
      q3: 'qualifying' as const,
      sprint: 'race' as const,
      main: 'race' as const,
      timeTrial: 'practice' as const,
    };

    return {
      id: race.id,
      leagueId: race.leagueId,
      scheduledAt: race.scheduledAt.toISOString(),
      track: race.track,
      trackId: race.trackId ?? '',
      car: race.car,
      carId: race.carId ?? '',
      sessionType: sessionTypeMap[race.sessionType.value],
      status: race.status,
      ...(race.strengthOfField !== undefined
        ? { strengthOfField: race.strengthOfField }
        : {}),
      ...(race.registeredCount !== undefined
        ? { registeredCount: race.registeredCount }
        : {}),
      ...(race.maxParticipants !== undefined
        ? { maxParticipants: race.maxParticipants }
        : {}),
    };
  }

  static toRaceDTOs(races: Race[]): RaceDTO[] {
    const sessionTypeMap = {
      practice: 'practice' as const,
      qualifying: 'qualifying' as const,
      q1: 'qualifying' as const,
      q2: 'qualifying' as const,
      q3: 'qualifying' as const,
      sprint: 'race' as const,
      main: 'race' as const,
      timeTrial: 'practice' as const,
    };

    return races.map((race) => ({
      id: race.id,
      leagueId: race.leagueId,
      scheduledAt: race.scheduledAt.toISOString(),
      track: race.track,
      trackId: race.trackId ?? '',
      car: race.car,
      carId: race.carId ?? '',
      sessionType: sessionTypeMap[race.sessionType.value],
      status: race.status,
      ...(race.strengthOfField !== undefined
        ? { strengthOfField: race.strengthOfField }
        : {}),
      ...(race.registeredCount !== undefined
        ? { registeredCount: race.registeredCount }
        : {}),
      ...(race.maxParticipants !== undefined
        ? { maxParticipants: race.maxParticipants }
        : {}),
    }));
  }

  static toResultDTO(result: Result | null): ResultDTO | null {
    if (!result) return null;
    return {
      id: result.id,
      raceId: result.raceId,
      driverId: result.driverId,
      position: result.position,
      fastestLap: result.fastestLap,
      incidents: result.incidents,
      startPosition: result.startPosition,
    };
  }

  static toResultDTOs(results: Result[]): ResultDTO[] {
    return results.map(result => ({
      id: result.id,
      raceId: result.raceId,
      driverId: result.driverId,
      position: result.position,
      fastestLap: result.fastestLap,
      incidents: result.incidents,
      startPosition: result.startPosition,
    }));
  }

  static toStandingDTO(standing: Standing | null): StandingDTO | null {
    if (!standing) return null;
    return {
      leagueId: standing.leagueId,
      driverId: standing.driverId,
      points: standing.points,
      wins: standing.wins,
      position: standing.position,
      racesCompleted: standing.racesCompleted,
    };
  }

  static toStandingDTOs(standings: Standing[]): StandingDTO[] {
    return standings.map(standing => ({
      leagueId: standing.leagueId,
      driverId: standing.driverId,
      points: standing.points,
      wins: standing.wins,
      position: standing.position,
      racesCompleted: standing.racesCompleted,
    }));
  }
}