using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using Sched.CustomClasses;

namespace Sched.ScheduleAlgorithm
{
    public class GreedyAlgorithm: BaseAlgorithm
    {
        public GreedyAlgorithm(int dayStart, int dayEnd, int periodStart, int periodEnd, int semesterId, int studentGroupId, int lessonTypePreference):base(dayStart, dayEnd, periodStart, periodEnd, semesterId, studentGroupId, lessonTypePreference)
        {

        }

        public List<Lesson> Run(List<Lesson> lessonList)
        {
            //Prepare new list
            List<Lesson> assignedLessons = new List<Lesson>();

            //Preprocess
            List<LessonWithArray> lessonsToAssign = PrepareLessons(lessonList);

            int lssnCount = lessonList.Count;
            for (int i = 0; i < lssnCount; i++)
            {
                //Get lesson with minimum possible placements
                int minScore = int.MaxValue;
                int minIndex = 0;
                for (int j = 0; j < lessonsToAssign.Count; j++)
                {
                    LessonWithArray lwa = lessonsToAssign[j];
                    int lwaScore = lwa.RecalculateEmptySpotsScore(_dayStart, _dayEnd, _periodStart, _periodEnd);
                    if (lwaScore < minScore)
                    {
                        minScore = lwaScore;
                        minIndex = j;
                    }
                }

                //Get possible positions
                List<(int day, int period, int week)> possiblePos = lessonsToAssign[minIndex].GetPossiblePositions(_dayStart, _dayEnd, _periodStart, _periodEnd);
                if (possiblePos.Count > 0)
                {
                    //Score them and choose best
                    int bestFitScore = int.MaxValue;
                    for (int j = 0; j < possiblePos.Count; j++)
                    {
                        (int day, int period, int week) = possiblePos[j];
                        int variantScore = ScoreSingle(day, period, week, lessonsToAssign[minIndex].Lssn.Hours, lessonsToAssign[minIndex].Lssn.CourseId, lessonsToAssign[minIndex].Lssn.LessonTypeId);
                        if (variantScore < bestFitScore)
                        {
                            bestFitScore = variantScore;
                            lessonsToAssign[minIndex].Lssn.PeriodStart = period;
                            lessonsToAssign[minIndex].Lssn.StartDateDT = _sem.DateStartDT.AddDays(week * 7 + day);
                        }
                    }
                    Lesson bestVarLesson = lessonsToAssign[minIndex].Lssn;

                    //Assign lesson and remove it
                    assignedLessons.Add(new Lesson(bestVarLesson));
                    InsertLesson(bestVarLesson);

                    //Update rest and remove assigned lesson
                    for (int j = 0; j < lessonsToAssign.Count; j++)
                    {
                        lessonsToAssign[j].MarkOccupiedSingleLesson(bestVarLesson, _sem,true);
                    }
                }
                lessonsToAssign.RemoveAt(minIndex);
            }
            return assignedLessons;
        }
    }
}
