using Core.Calculation;
using Core.Entities;
using Tests.Builders;
using Tests.Fixtures;

namespace Tests.Calculation;

[TestFixture]
public class TeamSchedulerTest
{
	[SetUp]
	public void SetUp()
	{
		BuilderExtensions.ResetAllBuilders();
	}

	[Test]
	public void Prototype_Test()
	{
		var teamSchedulerTest = new TeamScheduler_Prototype();
		teamSchedulerTest.Solve();
	}

	[Test]
	public void SolutionTest()
	{
		// Create test data with regional team events for TeamScheduler
		var robotics = EventDefinitionBuilder.Team("Robotics", 2, 5).AsRegionalEvent().Build();
		var biotech = EventDefinitionBuilder.Team("Biotechnology", 2, 6).AsRegionalEvent().Build();
		var webDesign = EventDefinitionBuilder.Team("Website Design", 3, 6).AsRegionalEvent().Build();
		var videoGame = EventDefinitionBuilder.Team("Video Game Design", 2, 6).AsRegionalEvent().Build();
		var engineering = EventDefinitionBuilder.Team("Engineering Design", 3, 6).AsRegionalEvent().Build();
		var cybersecurity = EventDefinitionBuilder.Team("Cybersecurity", 2, 6).AsRegionalEvent().Build();

		var events = new[] { robotics, biotech, webDesign, videoGame, engineering, cybersecurity };

		// Create students
		var alice = StudentBuilder.Default().WithName("Alice", "A").WithGrade(9).WithTsaYear(1).Build();
		var bob = StudentBuilder.Default().WithName("Bob", "B").WithGrade(10).WithTsaYear(2).Build();
		var carol = StudentBuilder.Default().WithName("Carol", "C").WithGrade(11).WithTsaYear(3).Build();
		var david = StudentBuilder.Default().WithName("David", "D").WithGrade(9).WithTsaYear(1).Build();
		var eve = StudentBuilder.Default().WithName("Eve", "E").WithGrade(10).WithTsaYear(2).Build();
		var frank = StudentBuilder.Default().WithName("Frank", "F").WithGrade(11).WithTsaYear(3).Build();
		var grace = StudentBuilder.Default().WithName("Grace", "G").WithGrade(9).WithTsaYear(1).Build();
		var henry = StudentBuilder.Default().WithName("Henry", "H").WithGrade(10).WithTsaYear(2).Build();

		var students = new[] { alice, bob, carol, david, eve, frank, grace, henry };

		// Create teams with student assignments
		var allTeams = new[]
		{
			TeamBuilder.Default().ForEvent(robotics).WithStudentsAndCaptain(alice, bob, carol).WithIdentifier("Robotics A").Build(),
			TeamBuilder.Default().ForEvent(biotech).WithStudentsAndCaptain(david, eve, frank).WithIdentifier("Biotech A").Build(),
			TeamBuilder.Default().ForEvent(webDesign).WithStudentsAndCaptain(grace, henry, alice).WithIdentifier("WebDesign A").Build(),
			TeamBuilder.Default().ForEvent(videoGame).WithStudentsAndCaptain(bob, david).WithIdentifier("VideoGame A").Build(),
			TeamBuilder.Default().ForEvent(engineering).WithStudentsAndCaptain(carol, eve, frank).WithIdentifier("Engineering A").Build(),
			TeamBuilder.Default().ForEvent(cybersecurity).WithStudentsAndCaptain(grace, henry).WithIdentifier("Cybersecurity A").Build()
		};

		// Filter to only regional team events (matching original test logic)
		var teams = allTeams
			.Where(t => t.Event.EventFormat == EventFormat.Team && t.Event.RegionalEvent)
			.ToArray();

		// Verify we have teams to schedule
		Assert.That(teams, Is.Not.Empty, "Should have teams to schedule");

		// Run TeamScheduler with 3 time slots
		var teamScheduler = new TeamScheduler(teams, 3, students);
		var solution = teamScheduler.Solve();

		// Verify solution
		Assert.That(solution, Is.Not.Null);
		Assert.That(solution.TimeSlots, Is.Not.Null);
		Assert.That(solution.TimeSlots.Length, Is.EqualTo(3), "Should have 3 time slots");

		// Print solution (matching original test output format)
		var i = 1;
		foreach (var slot in solution.TimeSlots)
		{
			Console.WriteLine($"Time slot {i++}");
			foreach (var team in slot.Teams.OrderBy(s => s.Event.Name))
			{
				var names = string.Join(", ", team.Students.OrderByDescending(s => s.Grade + s.TsaYear).Select(s => s.FirstName));
				Console.WriteLine($"\t{team.Event.Name}");
				Console.WriteLine($"\t\t{names}");
			}

			var overlaps = TeamSchedulerSolution.GetStudentTeamOverlaps(slot.Teams).ToList();

			if (overlaps.Any())
			{
				Console.WriteLine("\toverlaps");
				foreach (var overlap in overlaps)
					Console.WriteLine(
						$"\t\t{overlap.student.Name} : {string.Join(", ", overlap.teams.Select(t => t.Event.Name))}");
			}

			var unassigned = UnassignedStudentScheduler.UnassignedStudents(students, slot.Teams).ToList();

			if (unassigned.Any())
				Console.WriteLine("\tunassigned");
			Console.WriteLine($"\t\t{string.Join(", ", unassigned.Select(s => s.FirstName))}");
		}
	}
}