using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Text;

namespace Sched.CustomClasses
{
    public class Semester : INotifyPropertyChanged
    {
        private int _id = 0;
        private int _semesterTypeId = 0;
        private DateTime _dateStartDT;
        private DateTime _dateEndDT;
        private int _academicStartYear;

        private string _semesterTypeName = string.Empty;

        public int Id
        {
            get { return _id; }
            set
            { _id = value;
              //_semesterTypeName = "Winter"; //get actual value from database
              OnPropertyChanged("Id"); 
            }
        }
        public int SemesterTypeId
        {
            get { return _semesterTypeId; }
            set { _semesterTypeId = value; OnPropertyChanged("SemesterTypeId"); }
        }
        public DateTime DateStartDT
        {
            get { return _dateStartDT; }
            set
            {
                _dateStartDT = value;
                //_dateStart = value.ToString("s", System.Globalization.CultureInfo.InvariantCulture);
                OnPropertyChanged("DateStartDT");
            }
        }
        public DateTime DateEndDT
        {
            get { return _dateEndDT; }
            set
            {
                _dateEndDT = value;
                //_dateEnd = value.ToString("s", System.Globalization.CultureInfo.InvariantCulture);
                OnPropertyChanged("DateEndDT");
            }
        }
        public int AcademicStartYear
        {
            get { return _academicStartYear; }
            set
            {
                if ((value>0)&&(value < 9999))
                {
                    _academicStartYear = value;
                    OnPropertyChanged("AcademicStartYear");
                }
            }
        }


        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string info)
        {
            var handler = PropertyChanged;
            handler?.Invoke(this, new PropertyChangedEventArgs(info));
        }

        public Semester()
        {
            this.DateStartDT = DateTime.Today;
            this.DateEndDT = DateTime.Today;
            this.AcademicStartYear = DateStartDT.Year;
        }
        public Semester(int Id, int SemesterTypeId,DateTime StartDateDT, DateTime EndDateDT, int AcademicStartYear)
        {
            this.Id = Id;
            this.SemesterTypeId = SemesterTypeId;
            this.DateStartDT = StartDateDT;
            this.DateEndDT = EndDateDT;
            this.AcademicStartYear = AcademicStartYear;
        }

        public int GetNumberOfWeeks()
        {
            int nDays = (int)(DateEndDT.Date - DateStartDT.Date).TotalDays;
            if ((nDays % 7) != 0)   //does not give an integer number of weeks
            {
                nDays += 7 - (nDays % 7);
            }

            return nDays / 7;
        }

        public int GetWeek(DateTime d)
        {
            int nDays = (int)(d.Date - DateStartDT.Date).TotalDays;
            return nDays / 7;
        }
        public int GetHoursTotal(DateTime lessonStartDT, int lessonPeriodicity, int lessonHours)
        {
            int nWeeks = GetNumberOfWeeks();    //is true if lessonPeriodicity is 1 aka happens every week
            if (lessonPeriodicity == 0) //lesson repeats with periodicity of 0 weeks -> lesson does not repeat, it's a single-time event
            {
                nWeeks = 1;
            }
            else if (lessonPeriodicity == 2) //lesson repeats every two weeks
            {
                int nDays = (int)(lessonStartDT.Date - DateStartDT.Date).TotalDays;
                if (nDays < 7)  //lesson takes place in the first week 
                {
                    nWeeks = (int) Math.Ceiling((double)nWeeks/2.0);    //must round up in case nWeeks is an odd number
                }
                else
                {
                    nWeeks = nWeeks - (int)Math.Ceiling((double)nWeeks / 2.0);
                }
            } 

            return nWeeks * lessonHours;
        }

        static public int GetWeekParity(DateTime lessonStartDT)
        {
            int weekParity = 2; //assumed even week
            int week = ISOWeek.GetWeekOfYear(lessonStartDT);
            if ((week % 2) == 1 )
            {
                weekParity = 1; //odd week
            }

            return weekParity;
        }

        public List<string> GetAllDatesOfDayOfWeek(DateTime lessonStartDT)
        {
            List<string> weekdayDateList = new List<string>();
            DateTime currentDate = DateStartDT;
            while(currentDate.DayOfWeek != lessonStartDT.DayOfWeek)
            {
                currentDate = currentDate.AddDays(1.0);
                //Debug.WriteLine(currentDate.DayOfWeek.ToString() + lessonStartDT.DayOfWeek.ToString());
                //Debug.WriteLine(currentDate.ToString());
            }

            for(int i = 0; currentDate < DateEndDT ; i++)
            {
                weekdayDateList.Add(currentDate.ToString());
                currentDate = currentDate.AddDays(7.0);
                //Debug.WriteLine(i.ToString() + " "+ currentDate.ToString());
            }

            return weekdayDateList;
        }

        public bool IsInCollision(Lesson lssnA, Lesson lssnB)
        {
            if (!(IsOverlapped(lssnA.PeriodStart, lssnA.PeriodStart + lssnA.Hours, lssnB.PeriodStart, lssnB.PeriodStart + lssnB.Hours)))
            {
                return false;     //lessons with non-overlaping hours cannot be in collision
            }

            if(lssnA.StartDateDT.Date.DayOfWeek == lssnB.StartDateDT.Date.DayOfWeek)    //only lessons in the same day of week can be in collision
            {
                if ((lssnA.Periodicity == 1) || (lssnB.Periodicity == 1))    //0 - a single-time event, 1-every week, 2 - every other week
                {
                    return true;
                }
                else if ((lssnA.Periodicity == 2) || (lssnB.Periodicity == 2))
                {
                    if (GetWeekParity(lssnA.StartDateDT) == GetWeekParity(lssnB.StartDateDT))
                    {
                        return true;
                    }
                }
                else   // combination 0,0
                {
                    if (lssnA.StartDateDT.Date == lssnB.StartDateDT.Date)
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        public bool IsOverlapped(int aStart, int aEnd, int bStart, int bEnd)
        {
            int result = Math.Max(0, Math.Min(aEnd, bEnd) - Math.Max(aStart, bStart));
            if (result > 0) //if true -> there is an overlap of intervals
            {
                return true;
            }

            return false;
        }

        public override string ToString()
        {
            string semesterTypeName = DBI.SelectReturnSingleValue("SemesterType", "Name", _semesterTypeId);
            return $"{_academicStartYear}/{_academicStartYear + 1} {semesterTypeName} ({_id})";
        }
    }

    public class SemesterType : INotifyPropertyChanged
    {
        private int _id;
        private string _name;
        public int Id
        {
            get { return _id; }
            set { _id = value; OnPropertyChanged("Id"); }
        }
        public string Name
        {
            get { return _name; }
            set { _name = value; OnPropertyChanged("Name"); }
        }

        public SemesterType()
        {
            _id = 0;
            _name = string.Empty;
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string info)
        {
            var handler = PropertyChanged;
            handler?.Invoke(this, new PropertyChangedEventArgs(info));
        }

        public override string ToString()
        {
            return $"{_id} - {_name}";
        }
    }
}
