import { League, LeagueSettings } from '@core/racing/domain/entities/League';
import { Driver } from '@core/racing/domain/entities/Driver';
import { MediaReference } from '@core/domain/media/MediaReference';
import { faker } from '@faker-js/faker';
import { seedId } from './SeedIdHelper';

export class RacingLeagueFactory {
  constructor(
    private readonly baseDate: Date,
    private readonly drivers: Driver[],
    private readonly persistence: 'postgres' | 'inmemory' = 'inmemory',
  ) {}

  create(): League[] {
    const leagueCount = 120; // Expanded to 100+ leagues

    // Create diverse league configurations covering ALL enum combinations
    // Points systems: f1-2024, indycar, custom (3)
    // Qualifying formats: single-lap, open (2)
    // Visibility: ranked, unranked (2)
    // Decision modes: admin_only, steward_decides, steward_vote, member_vote, steward_veto, member_veto (6)
    // Total combinations: 3 * 2 * 2 * 6 = 72, but we'll sample 30 covering extremes
    
    // Category types for leagues
    
    const leagueConfigs = [
      // 1-5: Ranked, F1-2024, various stewarding
      {
        pointsSystem: 'f1-2024' as const,
        qualifyingFormat: 'single-lap' as const,
        visibility: 'ranked' as const,
        maxDrivers: 40,
        sessionDuration: 60,
        stewarding: { decisionMode: 'admin_only' as const, requireDefense: false }
      },
      {
        pointsSystem: 'f1-2024' as const,
        qualifyingFormat: 'open' as const,
        visibility: 'ranked' as const,
        maxDrivers: 32,
        sessionDuration: 45,
        stewarding: { decisionMode: 'steward_vote' as const, requiredVotes: 3, requireDefense: true, defenseTimeLimit: 24 }
      },
      {
        pointsSystem: 'f1-2024' as const,
        qualifyingFormat: 'single-lap' as const,
        visibility: 'ranked' as const,
        maxDrivers: 50,
        sessionDuration: 90,
        stewarding: { decisionMode: 'member_vote' as const, requiredVotes: 5, requireDefense: false }
      },
      {
        pointsSystem: 'f1-2024' as const,
        qualifyingFormat: 'open' as const,
        visibility: 'ranked' as const,
        maxDrivers: 24,
        sessionDuration: 30,
        stewarding: { decisionMode: 'steward_veto' as const, requiredVotes: 2, requireDefense: true }
      },
      {
        pointsSystem: 'f1-2024' as const,
        qualifyingFormat: 'single-lap' as const,
        visibility: 'ranked' as const,
        maxDrivers: 60,
        sessionDuration: 120,
        stewarding: { decisionMode: 'member_veto' as const, requiredVotes: 4, requireDefense: false }
      },
      
      // 6-10: Ranked, IndyCar, various stewarding
      {
        pointsSystem: 'indycar' as const,
        qualifyingFormat: 'open' as const,
        visibility: 'ranked' as const,
        maxDrivers: 28,
        sessionDuration: 75,
        stewarding: { decisionMode: 'steward_decides' as const, requireDefense: true, defenseTimeLimit: 48 }
      },
      {
        pointsSystem: 'indycar' as const,
        qualifyingFormat: 'single-lap' as const,
        visibility: 'ranked' as const,
        maxDrivers: 36,
        sessionDuration: 60,
        stewarding: { decisionMode: 'admin_only' as const, requireDefense: false }
      },
      {
        pointsSystem: 'indycar' as const,
        qualifyingFormat: 'open' as const,
        visibility: 'ranked' as const,
        maxDrivers: 44,
        sessionDuration: 100,
        stewarding: { decisionMode: 'steward_vote' as const, requiredVotes: 4, requireDefense: true, voteTimeLimit: 72 }
      },
      {
        pointsSystem: 'indycar' as const,
        qualifyingFormat: 'single-lap' as const,
        visibility: 'ranked' as const,
        maxDrivers: 20,
        sessionDuration: 45,
        stewarding: { decisionMode: 'member_vote' as const, requiredVotes: 6, requireDefense: false }
      },
      {
        pointsSystem: 'indycar' as const,
        qualifyingFormat: 'open' as const,
        visibility: 'ranked' as const,
        maxDrivers: 48,
        sessionDuration: 110,
        stewarding: { decisionMode: 'steward_veto' as const, requiredVotes: 3, requireDefense: true }
      },

      // 11-15: Ranked, Custom, various stewarding
      {
        pointsSystem: 'custom' as const,
        qualifyingFormat: 'single-lap' as const,
        visibility: 'ranked' as const,
        maxDrivers: 32,
        sessionDuration: 50,
        stewarding: { decisionMode: 'member_veto' as const, requiredVotes: 5, requireDefense: false }
      },
      {
        pointsSystem: 'custom' as const,
        qualifyingFormat: 'open' as const,
        visibility: 'ranked' as const,
        maxDrivers: 40,
        sessionDuration: 85,
        stewarding: { decisionMode: 'admin_only' as const, requireDefense: false }
      },
      {
        pointsSystem: 'custom' as const,
        qualifyingFormat: 'single-lap' as const,
        visibility: 'ranked' as const,
        maxDrivers: 52,
        sessionDuration: 95,
        stewarding: { decisionMode: 'steward_decides' as const, requireDefense: true, defenseTimeLimit: 36 }
      },
      {
        pointsSystem: 'custom' as const,
        qualifyingFormat: 'open' as const,
        visibility: 'ranked' as const,
        maxDrivers: 26,
        sessionDuration: 65,
        stewarding: { decisionMode: 'steward_vote' as const, requiredVotes: 2, requireDefense: false }
      },
      {
        pointsSystem: 'custom' as const,
        qualifyingFormat: 'single-lap' as const,
        visibility: 'ranked' as const,
        maxDrivers: 56,
        sessionDuration: 105,
        stewarding: { decisionMode: 'member_vote' as const, requiredVotes: 7, requireDefense: true, protestDeadlineHours: 24 }
      },

      // 16-20: Unranked, F1-2024, various stewarding (smaller, no participant requirements)
      {
        pointsSystem: 'f1-2024' as const,
        qualifyingFormat: 'open' as const,
        visibility: 'unranked' as const,
        maxDrivers: 8,
        sessionDuration: 30,
        stewarding: { decisionMode: 'admin_only' as const, requireDefense: false }
      },
      {
        pointsSystem: 'f1-2024' as const,
        qualifyingFormat: 'single-lap' as const,
        visibility: 'unranked' as const,
        maxDrivers: 12,
        sessionDuration: 45,
        stewarding: { decisionMode: 'steward_decides' as const, requireDefense: true }
      },
      {
        pointsSystem: 'f1-2024' as const,
        qualifyingFormat: 'open' as const,
        visibility: 'unranked' as const,
        maxDrivers: 16,
        sessionDuration: 60,
        stewarding: { decisionMode: 'steward_vote' as const, requiredVotes: 2, requireDefense: false }
      },
      {
        pointsSystem: 'f1-2024' as const,
        qualifyingFormat: 'single-lap' as const,
        visibility: 'unranked' as const,
        maxDrivers: 10,
        sessionDuration: 35,
        stewarding: { decisionMode: 'member_vote' as const, requiredVotes: 3, requireDefense: true }
      },
      {
        pointsSystem: 'f1-2024' as const,
        qualifyingFormat: 'open' as const,
        visibility: 'unranked' as const,
        maxDrivers: 20,
        sessionDuration: 55,
        stewarding: { decisionMode: 'steward_veto' as const, requiredVotes: 2, requireDefense: false }
      },

      // 21-25: Unranked, IndyCar, various stewarding
      {
        pointsSystem: 'indycar' as const,
        qualifyingFormat: 'single-lap' as const,
        visibility: 'unranked' as const,
        maxDrivers: 14,
        sessionDuration: 40,
        stewarding: { decisionMode: 'member_veto' as const, requiredVotes: 3, requireDefense: true }
      },
      {
        pointsSystem: 'indycar' as const,
        qualifyingFormat: 'open' as const,
        visibility: 'unranked' as const,
        maxDrivers: 18,
        sessionDuration: 50,
        stewarding: { decisionMode: 'admin_only' as const, requireDefense: false }
      },
      {
        pointsSystem: 'indycar' as const,
        qualifyingFormat: 'single-lap' as const,
        visibility: 'unranked' as const,
        maxDrivers: 22,
        sessionDuration: 65,
        stewarding: { decisionMode: 'steward_decides' as const, requireDefense: true, defenseTimeLimit: 12 }
      },
      {
        pointsSystem: 'indycar' as const,
        qualifyingFormat: 'open' as const,
        visibility: 'unranked' as const,
        maxDrivers: 6,
        sessionDuration: 25,
        stewarding: { decisionMode: 'steward_vote' as const, requiredVotes: 2, requireDefense: false }
      },
      {
        pointsSystem: 'indycar' as const,
        qualifyingFormat: 'single-lap' as const,
        visibility: 'unranked' as const,
        maxDrivers: 24,
        sessionDuration: 70,
        stewarding: { decisionMode: 'member_vote' as const, requiredVotes: 4, requireDefense: true }
      },

      // 26-30: Unranked, Custom, various stewarding
      {
        pointsSystem: 'custom' as const,
        qualifyingFormat: 'open' as const,
        visibility: 'unranked' as const,
        maxDrivers: 12,
        sessionDuration: 35,
        stewarding: { decisionMode: 'steward_veto' as const, requiredVotes: 2, requireDefense: false }
      },
      {
        pointsSystem: 'custom' as const,
        qualifyingFormat: 'single-lap' as const,
        visibility: 'unranked' as const,
        maxDrivers: 16,
        sessionDuration: 45,
        stewarding: { decisionMode: 'member_veto' as const, requiredVotes: 3, requireDefense: true }
      },
      {
        pointsSystem: 'custom' as const,
        qualifyingFormat: 'open' as const,
        visibility: 'unranked' as const,
        maxDrivers: 20,
        sessionDuration: 55,
        stewarding: { decisionMode: 'admin_only' as const, requireDefense: false }
      },
      {
        pointsSystem: 'custom' as const,
        qualifyingFormat: 'single-lap' as const,
        visibility: 'unranked' as const,
        maxDrivers: 8,
        sessionDuration: 30,
        stewarding: { decisionMode: 'steward_decides' as const, requireDefense: true, defenseTimeLimit: 18 }
      },
      {
        pointsSystem: 'custom' as const,
        qualifyingFormat: 'open' as const,
        visibility: 'unranked' as const,
        maxDrivers: 24,
        sessionDuration: 60,
        stewarding: { decisionMode: 'steward_vote' as const, requiredVotes: 3, requireDefense: false }
      },
    ];

    return Array.from({ length: leagueCount }, (_, idx) => {
      const i = idx + 1;
      const owner = faker.helpers.arrayElement(this.drivers);
      // Cycle through the 30 configs for variety
      const config = leagueConfigs[idx % 30]!;

      const createdAt =
        // Ensure some "New" leagues (created within 7 days) so `/leagues` featured categories are populated.
        idx % 6 === 0
          ? faker.date.recent({ days: 6, refDate: this.baseDate })
          : faker.date.past({ years: 2, refDate: this.baseDate });

      // Calculate participant count based on visibility and league
      let participantCount: number;
      if (config.visibility === 'ranked') {
        // Ranked leagues need >= 10 participants
        // Some are full (max), some have minimum, some have none
        if (idx % 5 === 0) {
          participantCount = config.maxDrivers; // Full league
        } else if (idx % 3 === 0) {
          participantCount = 12; // Just meets minimum
        } else if (idx % 7 === 0) {
          participantCount = 0; // Empty but valid
        } else {
          participantCount = faker.number.int({ min: 10, max: config.maxDrivers - 5 });
        }
      } else {
        // Unranked can have any count, but must have at least 2 if not empty
        if (idx % 4 === 0) {
          participantCount = config.maxDrivers; // Full
        } else if (idx % 5 === 0) {
          participantCount = 0; // Empty
        } else {
          participantCount = faker.number.int({ min: 2, max: Math.min(config.maxDrivers, 15) });
        }
      }

      // Determine category based on scoring configuration
      let category: string | undefined;
      if (config.pointsSystem === 'f1-2024') {
        if (config.qualifyingFormat === 'single-lap') {
          category = 'driver';
        } else {
          category = 'team';
        }
      } else if (config.pointsSystem === 'indycar') {
        category = 'nations';
      } else if (config.pointsSystem === 'custom') {
        category = 'trophy';
      }
      
      // Override some leagues to have endurance or sprint categories
      if (idx % 8 === 0) {
        category = 'endurance';
      } else if (idx % 7 === 0) {
        category = 'sprint';
      }

      // Build the league data object
      const leagueData = {
        id: seedId(`league-${i}`, this.persistence),
        name: faker.company.name() + ' Racing League',
        description: faker.lorem.sentences(2),
        ownerId: owner.id.toString(),
        settings: {
          pointsSystem: config.pointsSystem,
          maxDrivers: config.maxDrivers,
          sessionDuration: config.sessionDuration,
          qualifyingFormat: config.qualifyingFormat,
          visibility: config.visibility,
          stewarding: {
            ...config.stewarding,
            voteTimeLimit: 72,
            protestDeadlineHours: 48,
            stewardingClosesHours: 168,
            notifyAccusedOnProtest: true,
            notifyOnVoteRequired: true,
          },
        },
        category,
        createdAt,
        participantCount,
      };

      // Add social links with varying completeness
      const socialLinks: { discordUrl?: string; youtubeUrl?: string; websiteUrl?: string } = {};
      const socialLinkTypes = ['discord', 'youtube', 'website'] as const;

      // Ensure some leagues have no social links, some have partial, some have all
      const numSocialLinks = idx % 4; // 0, 1, 2, or 3
      const selectedTypes = faker.helpers.arrayElements(socialLinkTypes, numSocialLinks);

      selectedTypes.forEach(type => {
        if (type === 'discord') socialLinks.discordUrl = faker.internet.url();
        if (type === 'youtube') socialLinks.youtubeUrl = faker.internet.url();
        if (type === 'website') socialLinks.websiteUrl = faker.internet.url();
      });

      // Create the final league data with optional fields
      const finalLeagueData: {
        id: string;
        name: string;
        description: string;
        ownerId: string;
        settings?: Partial<LeagueSettings>;
        category?: string | undefined;
        createdAt?: Date;
        socialLinks?: {
          discordUrl?: string;
          youtubeUrl?: string;
          websiteUrl?: string;
        };
        participantCount?: number;
        logoRef?: MediaReference;
      } = {
        id: leagueData.id,
        name: leagueData.name,
        description: leagueData.description,
        ownerId: leagueData.ownerId,
        settings: leagueData.settings,
        category: leagueData.category,
        createdAt: leagueData.createdAt,
        participantCount: leagueData.participantCount,
        logoRef: MediaReference.generated('league', leagueData.id),
      };

      if (Object.keys(socialLinks).length > 0) {
        finalLeagueData.socialLinks = socialLinks;
      }

      return League.create(finalLeagueData);
    });
  }
}