using Core.Entities;
using Tests.Builders;

namespace Tests.Fixtures;

/// <summary>
/// Pre-configured test data fixtures for different testing scenarios.
/// </summary>
public static class TestDataFixtures
{
    /// <summary>
    /// Small dataset for simple unit tests (5 events, 6 students, minimal teams).
    /// </summary>
    public static class Small
    {
        /// <summary>
        /// Returns a small set of test data: 5 events, 6 students, and 3 teams.
        /// Suitable for simple unit tests that don't require realistic volume.
        /// </summary>
        public static (EventDefinition[] Events, Student[] Students, Team[] Teams) Full()
        {
            BuilderExtensions.ResetAllBuilders();

            var events = new[]
            {
                EventDefinitionBuilder.Individual("Flight").Build(),
                EventDefinitionBuilder.Individual("Coding").Build(),
                EventDefinitionBuilder.Team("Biotechnology", 2, 6).WithInterview().Build(),
                EventDefinitionBuilder.Team("Robotics", 2, 5).AsOnSite().Build(),
                EventDefinitionBuilder.Individual("Essays on Technology").Build()
            };

            var students = new[]
            {
                StudentBuilder.Default().WithName("Alice", "Anderson").WithGrade(9).Build(),
                StudentBuilder.Default().WithName("Bob", "Brown").WithGrade(10).Build(),
                StudentBuilder.Default().WithName("Carol", "Clark").WithGrade(11).Build(),
                StudentBuilder.Default().WithName("David", "Davis").WithGrade(9).Build(),
                StudentBuilder.Default().WithName("Eve", "Evans").WithGrade(10).Build(),
                StudentBuilder.Default().WithName("Frank", "Foster").WithGrade(11).Build()
            };

            var teams = new[]
            {
                TeamBuilder.Default().ForEvent(events[2]) // Biotechnology
                    .WithStudentsAndCaptain(students[0], students[1])
                    .Build(),
                TeamBuilder.Default().ForEvent(events[3]) // Robotics
                    .WithStudentsAndCaptain(students[2], students[3], students[4])
                    .Build(),
                TeamBuilder.Default().ForEvent(events[0]) // Flight (individual)
                    .WithStudent(students[5])
                    .Build()
            };

            return (events, students, teams);
        }

        /// <summary>
        /// Returns just events from the small fixture.
        /// </summary>
        public static EventDefinition[] Events()
        {
            BuilderExtensions.ResetAllBuilders();
            return Full().Events;
        }

        /// <summary>
        /// Returns just students from the small fixture.
        /// </summary>
        public static Student[] Students()
        {
            BuilderExtensions.ResetAllBuilders();
            return Full().Students;
        }
    }

    /// <summary>
    /// Large dataset for algorithm tests requiring realistic volume (25 events, 18 students, 15+ teams).
    /// </summary>
    public static class Large
    {
        /// <summary>
        /// Returns a realistic large set of test data: 25 events, 18 students, and 15+ teams.
        /// Includes real TSA event names and realistic team configurations.
        /// Suitable for testing algorithms like EventAssignment and TeamScheduler.
        /// </summary>
        public static (EventDefinition[] Events, Student[] Students, Team[] Teams) Full()
        {
            BuilderExtensions.ResetAllBuilders();

            // Real TSA events with realistic configurations
            var events = new[]
            {
                // Individual events (some are regional)
                EventDefinitionBuilder.Individual("Architectural Design").WithStateCount(3).AsRegionalEvent().Build(),
                EventDefinitionBuilder.Individual("Biotechnology Design").WithInterview().AsRegionalEvent().Build(),
                EventDefinitionBuilder.Individual("Coding").WithStateCount(3).Build(),
                EventDefinitionBuilder.Individual("Digital Photography").AsRegionalEvent().Build(),
                EventDefinitionBuilder.Individual("Essays on Technology").Build(),
                EventDefinitionBuilder.Individual("Extemporaneous Speech").AsOnSite().Build(),
                EventDefinitionBuilder.Individual("Flight").WithStateCount(3).AsRegionalEvent().Build(),
                EventDefinitionBuilder.Individual("Prepared Speech").AsOnSite().Build(),
                EventDefinitionBuilder.Individual("Scientific Visualization").Build(),
                EventDefinitionBuilder.Individual("System Control Technology").Build(),

                // Team events (2-6 members, many are regional)
                EventDefinitionBuilder.Team("Animatronics", 2, 6).WithInterview().AsRegionalEvent().Build(),
                EventDefinitionBuilder.Team("Chapter Team", 6, 6).WithPresentation().Build(),
                EventDefinitionBuilder.Team("Cybersecurity", 2, 6).AsRegionalEvent().Build(),
                EventDefinitionBuilder.Team("Debate", 2, 2).AsOnSite().Build(),
                EventDefinitionBuilder.Team("Dragster", 1, 3).AsRegionalEvent().Build(),
                EventDefinitionBuilder.Team("Engineering Design", 3, 6).WithInterview().AsRegionalEvent().Build(),
                EventDefinitionBuilder.Team("Fashion Design", 2, 6).WithInterview().AsRegionalEvent().Build(),
                EventDefinitionBuilder.Team("Forensic Technology", 2, 6).Build(),
                EventDefinitionBuilder.Team("Future Technology Teacher", 2, 6).WithPresentation().AsRegionalEvent().Build(),
                EventDefinitionBuilder.Team("Junior Solar Sprint", 2, 3).AsRegionalEvent().Build(),
                EventDefinitionBuilder.Team("Music Production", 2, 6).WithInterview().AsRegionalEvent().Build(),
                EventDefinitionBuilder.Team("On Demand Video", 2, 6).Build(),
                EventDefinitionBuilder.Team("Promotional Marketing", 1, 6).WithPresentation().Build(),
                EventDefinitionBuilder.Team("Software Development", 2, 6).WithInterview().AsRegionalEvent().Build(),
                EventDefinitionBuilder.Team("Video Game Design", 2, 6).WithInterview().AsRegionalEvent().Build()
            };

            // 18 students with varied grades and rankings
            var students = new[]
            {
                StudentBuilder.Default().WithName("Alice", "Anderson").WithGrade(9).WithTsaYear(1).Build(),
                StudentBuilder.Default().WithName("Bob", "Brown").WithGrade(10).WithTsaYear(2).Build(),
                StudentBuilder.Default().WithName("Carol", "Clark").WithGrade(11).WithTsaYear(3).Build(),
                StudentBuilder.Default().WithName("David", "Davis").WithGrade(9).WithTsaYear(1).Build(),
                StudentBuilder.Default().WithName("Eve", "Evans").WithGrade(10).WithTsaYear(2).Build(),
                StudentBuilder.Default().WithName("Frank", "Foster").WithGrade(11).WithTsaYear(3).Build(),
                StudentBuilder.Default().WithName("Grace", "Garcia").WithGrade(9).WithTsaYear(1).Build(),
                StudentBuilder.Default().WithName("Henry", "Harris").WithGrade(10).WithTsaYear(2).Build(),
                StudentBuilder.Default().WithName("Ivy", "Irwin").WithGrade(11).WithTsaYear(3).Build(),
                StudentBuilder.Default().WithName("Jack", "Johnson").WithGrade(9).WithTsaYear(1).Build(),
                StudentBuilder.Default().WithName("Kelly", "King").WithGrade(10).WithTsaYear(2).Build(),
                StudentBuilder.Default().WithName("Leo", "Lopez").WithGrade(11).WithTsaYear(3).Build(),
                StudentBuilder.Default().WithName("Maria", "Martinez").WithGrade(9).WithTsaYear(1).Build(),
                StudentBuilder.Default().WithName("Noah", "Nelson").WithGrade(10).WithTsaYear(2).Build(),
                StudentBuilder.Default().WithName("Olivia", "O'Brien").WithGrade(11).WithTsaYear(3).Build(),
                StudentBuilder.Default().WithName("Paul", "Patel").WithGrade(9).WithTsaYear(1).Build(),
                StudentBuilder.Default().WithName("Quinn", "Quinn").WithGrade(10).WithTsaYear(2).Build(),
                StudentBuilder.Default().WithName("Rachel", "Robinson").WithGrade(11).WithTsaYear(3).Build()
            };

            // Add event rankings for students (realistic preferences)
            AddRankingsToStudent(students[0], events, new[] { 0, 2, 6, 10, 12 }); // Individual + teams
            AddRankingsToStudent(students[1], events, new[] { 1, 3, 11, 13, 16 });
            AddRankingsToStudent(students[2], events, new[] { 4, 5, 14, 17, 20 });
            AddRankingsToStudent(students[3], events, new[] { 6, 7, 15, 18, 21 });
            AddRankingsToStudent(students[4], events, new[] { 8, 9, 16, 19, 22 });
            AddRankingsToStudent(students[5], events, new[] { 0, 2, 12, 20, 23 });
            AddRankingsToStudent(students[6], events, new[] { 1, 3, 10, 13, 24 });
            AddRankingsToStudent(students[7], events, new[] { 4, 5, 11, 14, 15 });
            AddRankingsToStudent(students[8], events, new[] { 6, 7, 16, 17, 18 });
            AddRankingsToStudent(students[9], events, new[] { 8, 9, 19, 21, 22 });
            AddRankingsToStudent(students[10], events, new[] { 0, 10, 12, 14, 23 });
            AddRankingsToStudent(students[11], events, new[] { 1, 11, 13, 15, 24 });
            AddRankingsToStudent(students[12], events, new[] { 2, 12, 16, 18, 20 });
            AddRankingsToStudent(students[13], events, new[] { 3, 13, 17, 19, 21 });
            AddRankingsToStudent(students[14], events, new[] { 4, 14, 18, 20, 22 });
            AddRankingsToStudent(students[15], events, new[] { 5, 15, 19, 21, 23 });
            AddRankingsToStudent(students[16], events, new[] { 6, 16, 20, 22, 24 });
            AddRankingsToStudent(students[17], events, new[] { 7, 10, 11, 12, 13 });

            // Create representative teams (some will be created by algorithm tests)
            var teams = new[]
            {
                TeamBuilder.Default().ForEvent(events[10]) // Animatronics
                    .WithStudentsAndCaptain(students[0], students[1], students[2])
                    .WithIdentifier("Team A")
                    .Build(),
                TeamBuilder.Default().ForEvent(events[11]) // Chapter Team
                    .WithStudentsAndCaptain(students[3], students[4], students[5], students[6], students[7], students[8])
                    .WithIdentifier("Chapter")
                    .Build(),
                TeamBuilder.Default().ForEvent(events[12]) // Cybersecurity
                    .WithStudentsAndCaptain(students[9], students[10])
                    .WithIdentifier("Team C")
                    .Build(),
                TeamBuilder.Default().ForEvent(events[13]) // Debate
                    .WithStudentsAndCaptain(students[11], students[12])
                    .WithIdentifier("Team D")
                    .Build(),
                TeamBuilder.Default().ForEvent(events[16]) // Fashion Design
                    .WithStudentsAndCaptain(students[13], students[14], students[15])
                    .WithIdentifier("Team F")
                    .Build(),
                TeamBuilder.Default().ForEvent(events[24]) // Video Game Design
                    .WithStudentsAndCaptain(students[16], students[17])
                    .WithIdentifier("Team V")
                    .Build()
            };

            return (events, students, teams);
        }

        /// <summary>
        /// Helper to add event rankings to a student.
        /// </summary>
        private static void AddRankingsToStudent(Student student, EventDefinition[] events, int[] eventIndices)
        {
            for (int i = 0; i < eventIndices.Length; i++)
            {
                var eventIndex = eventIndices[i];
                if (eventIndex >= 0 && eventIndex < events.Length)
                {
                    StudentEventRankingBuilder.Default()
                        .ForStudent(student)
                        .ForEvent(events[eventIndex])
                        .WithRank(i + 1)
                        .Build();
                }
            }
        }

        /// <summary>
        /// Returns just events from the large fixture.
        /// </summary>
        public static EventDefinition[] Events()
        {
            BuilderExtensions.ResetAllBuilders();
            return Full().Events;
        }

        /// <summary>
        /// Returns just students from the large fixture.
        /// </summary>
        public static Student[] Students()
        {
            BuilderExtensions.ResetAllBuilders();
            return Full().Students;
        }
    }

    /// <summary>
    /// Custom helpers for creating specific numbers of minimal test entities.
    /// </summary>
    public static class Custom
    {
        /// <summary>
        /// Creates N simple individual events with generic names.
        /// </summary>
        public static EventDefinition[] MinimalEvents(int count)
        {
            BuilderExtensions.ResetAllBuilders();
            var events = new EventDefinition[count];
            for (int i = 0; i < count; i++)
            {
                events[i] = EventDefinitionBuilder.Individual($"Event{i + 1}").Build();
            }
            return events;
        }

        /// <summary>
        /// Creates N simple students with sequential names.
        /// </summary>
        public static Student[] MinimalStudents(int count)
        {
            BuilderExtensions.ResetAllBuilders();
            return BuilderExtensions.CreateStudents(count);
        }

        /// <summary>
        /// Creates N simple teams for a given event.
        /// </summary>
        public static Team[] MinimalTeams(EventDefinition eventDef, int teamCount, int studentsPerTeam)
        {
            var allStudents = MinimalStudents(teamCount * studentsPerTeam);
            var teams = new Team[teamCount];

            for (int i = 0; i < teamCount; i++)
            {
                var teamStudents = allStudents.Skip(i * studentsPerTeam).Take(studentsPerTeam).ToArray();
                teams[i] = TeamBuilder.Default().ForEvent(eventDef)
                    .WithStudents(teamStudents)
                    .WithCaptain(teamStudents[0])
                    .WithIdentifier($"Team{i + 1}")
                    .Build();
            }

            return teams;
        }
    }
}
