using System.Globalization;
using Core.Entities;
using CsvHelper;
using CsvHelper.Configuration;
using FuzzySharp;

namespace Core.Parsers
{
	public class TeamWriter
	{
		private readonly ICollection<Team> _teams;

		public string Filename { get; }

		public TeamWriter(ICollection<Team> teams, string filename)
		{
			_teams = teams;
			Filename = filename;
		}

		public void Write()
		{
			var csvConfiguration = new CsvConfiguration(CultureInfo.CurrentCulture)
			{
				HasHeaderRecord = true,
			};

			using var writer = new StreamWriter(Filename);
			using var csv = new CsvWriter(writer, csvConfiguration);

			// header
			csv.WriteField("Team Name");
			csv.WriteField("Event Name");
			var max = _teams.Max(t => t.Students.Count);
			for (var i = 1; i < max + 1; i++)
			{
				csv.WriteField($"Student {i}");
			}
			
			foreach (var team in _teams)
			{
				csv.WriteField(team.Identifier);
				csv.WriteField(team.Event.Name);
				foreach (var teamStudent in team.Students)
				{
					csv.WriteField(teamStudent.Name);
				}
				csv.NextRecord();
			}
		}
	}

	public class TeamParser : CsvParserBase
	{
		public TeamParser(FileSystemInfo csvFile, bool ignoreBlankLines = true) : base(csvFile, ignoreBlankLines)
		{
		}

		public Team[] Parse(ICollection<EventDefinition> events, ICollection<Student> students)
		{
			var teams = new List<Team>();

			CsvReader.Read();
			CsvReader.ReadHeader();

			while (CsvReader.Read())
			{

				var eventName
					= CsvReader.GetField("Event Name");

				if (string.IsNullOrEmpty(eventName))
					continue;

				if (eventName.StartsWith("Team Size"))
					continue;

				eventName = eventName.Replace("ᵃ", string.Empty);
				eventName = eventName.Replace("ⁱ", string.Empty);
				eventName = eventName.TrimEnd();

				var teamName = CsvReader.GetField("Team Name");
				if (string.IsNullOrEmpty(teamName))
					teamName = eventName;

				eventName = eventName.Trim();

				var @event =
					(from e in events
						let rat = Fuzz.Ratio(e.Name, eventName)
						where rat > 50
						orderby rat descending
						select e).FirstOrDefault();

				if (@event == null)
					continue;

				var regionalTimeSlot = CsvReader.GetField("Regional Time Slot");
				if (!string.IsNullOrEmpty(regionalTimeSlot))
					regionalTimeSlot.Trim();

				var teamStudents = new List<Student>();
				Student? captain = null;

				for (var i = 1; i <= 9; i++)
				{
					var studentName = CsvReader.GetField($"Student {i}");
					if (string.IsNullOrEmpty(studentName)) continue;

					studentName = studentName.Trim();

					if (studentName == "?")
						continue;

					var studentMatches =
						from s in students
						let rat = new[]
						{
							Fuzz.Ratio(s.Name, studentName),
							Fuzz.Ratio(s.FirstNameLastName, studentName),
							Fuzz.Ratio(s.FirstName, studentName)
						}.Max()
						where rat > 90
						orderby rat descending
						select s;

					var student = studentMatches.FirstOrDefault();
					if (student == null)
					{
						//continue;
						throw new ArgumentException($"Student named '{studentName}' not found");
					}

					teamStudents.Add(student);
					if (i == 1)
						captain = student;
				}

				var teamNumber = string.Empty;
				if (teamName.EndsWith("Team 2"))
					teamNumber = "12227-2";
				else if (@event.EventFormat == EventFormat.Team)
					teamNumber = "2227";

				if (teamStudents.Count > 0)
				{
					if (@event.EventFormat is EventFormat.Team)
					{
						teams.Add(new Team {  Event = @event, Students = teamStudents, Captain = captain, Identifier = teamNumber});
					}
					else if (@event.EventFormat is EventFormat.Individual)
					{
						foreach (var student in teamStudents)
						{
							teams.Add(new Team{Event = @event,
								Students = [student], Captain = student, Identifier = teamNumber});
						}
					}
				}
			}

			return teams.ToArray();
		}
	}
}
