using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;
using System.Web.Http.Description;
using System.Web.Http.OData;
using iBemsDataService;
using iBemsDataService.Model;
using iBemsDataService.Util;

namespace iBemsDataService.Controllers
{
    public class AvailableDueDateController : ApiController
    {
        private iBemsEntities db = new iBemsEntities();

        [ActionName("GetAvailableDueDate")]
        public List<AvailableDueDateType> GetAvailableDueDate()
        {
            List<AvailableDueDateType> dueDateList = new List<AvailableDueDateType>();

            Uri uri = Request.RequestUri;
            var uriQuery = HttpUtility.ParseQueryString(uri.Query);
            int siteId, workRequestId;
            if (int.TryParse(uriQuery.Get("SiteId"), out siteId) == false ||
                int.TryParse(uriQuery.Get("WorkRequestId"), out workRequestId) == false)
            {
                dueDateList.Add(new AvailableDueDateType() { DueDate = DateTime.Now });
                return dueDateList;
            }

            // WorkRequest 정보

            var workRequest = (
                from w in db.FmsWorkRequest
                where w.SiteId == siteId &&
                    w.WorkRequestId == workRequestId
                select w).FirstOrDefault();

            if (workRequest == null || workRequest.WorkScheduleId == null)
            {
                dueDateList.Add(new AvailableDueDateType() { DueDate = DateTime.Now });
                return dueDateList;
            }

            // 스케줄 정보 
            var workSchedule = (
                from s in db.FmsWorkSchedule
                where s.SiteId == siteId &&
                    s.WorkScheduleId == workRequest.WorkScheduleId &&
                    s.IsUse == true
                select s)
            .FirstOrDefault();

            if (workSchedule == null)
            {
                dueDateList.Add(new AvailableDueDateType() { DueDate = DateTime.Now });
                return dueDateList;
            }
            var workResult = (
                from s in db.FmsWorkResult
                where s.SiteId == siteId &&
                    s.WorkRequestId == workRequestId
                select s)
            .FirstOrDefault();

            // 주기 간격 
            int cycleSize = workSchedule.CycleSize;
            // 현재일자
            //DateTime currentDueDate = DateTime.Now;
            // 종료일자
            DateTime EndDueDate = workResult.EndDate;
            // 확정일자
            DateTime plannDueDate = new DateTime();

            // 주기 유형
            // CycleUnitId :: 1: 일간 / 2: 주간 / 3: 월간 / 4: 분기 / 5: 반기 / 6: 년간
            switch (workSchedule.CycleUnitId)
            {
                case 1:
                    plannDueDate = EndDueDate.AddDays(cycleSize);
                    break;
                case 2:
                    plannDueDate = EndDueDate.AddDays(cycleSize * 7);
                    break;
                case 3:
                    plannDueDate = EndDueDate.AddMonths(cycleSize);
                    break;
                case 4:
                    plannDueDate = EndDueDate.AddMonths(cycleSize * 3);
                    break;
                case 5:
                    plannDueDate = EndDueDate.AddMonths(cycleSize * 6);
                    break;
                case 6:
                    plannDueDate = EndDueDate.AddYears(cycleSize);
                    break;
            }

            // 휴일근무 사용안함 인 경우 
            if (workSchedule.HolidayWorkTypeId == 0)
            {
                dueDateList.Add(new AvailableDueDateType() { DueDate = plannDueDate });
                return dueDateList;
            }

            // 휴일 리스트
            List<DateTime> holidayList = GetHolidayList(siteId);

            // 토요일, 일요일 휴무 여부
            bool isUseSaturdayHoliday = false;
            bool isUseSundayHoliday = false;

            var holidayWeekend = db.CmHolidayWeekend
                .Where(hw => hw.SiteId == siteId && hw.IsUse == true)
                .FirstOrDefault();

            if (holidayWeekend == null)
            {
                isUseSaturdayHoliday = true;
                isUseSundayHoliday = true;
            }
            else
            {
                isUseSaturdayHoliday = holidayWeekend.Saturday;
                isUseSundayHoliday = holidayWeekend.Sunday;
            }

            // 확정일자 계산
            bool isHoliday = CheckIsHoliday(plannDueDate, isUseSaturdayHoliday, isUseSundayHoliday, holidayList);

            // 휴일근무인 경우 
            if (workSchedule.HolidayWorkTypeId == 1)
            {
                while (!isHoliday)
                {
                    plannDueDate = plannDueDate.AddDays(1);
                    isHoliday = CheckIsHoliday(plannDueDate, isUseSaturdayHoliday, isUseSundayHoliday, holidayList);
                }
                dueDateList.Add(new AvailableDueDateType() { DueDate = plannDueDate });
                return dueDateList;
            }

            // 익일근무인 경우
            if (workSchedule.HolidayWorkTypeId == 2)
            {
                while (isHoliday)
                {
                    plannDueDate = plannDueDate.AddDays(1);
                    isHoliday = CheckIsHoliday(plannDueDate, isUseSaturdayHoliday, isUseSundayHoliday, holidayList);
                }
                dueDateList.Add(new AvailableDueDateType() { DueDate = plannDueDate });
                return dueDateList;
            }
            return dueDateList;
        }

        private bool CheckIsHoliday(DateTime plannDueDate, bool isUseSaturdayHoliday, bool isUseSundayHoliday, List<DateTime> holidayList)
        {
            // 토,일요일인 경우 리턴

            if (plannDueDate.DayOfWeek == DayOfWeek.Saturday && isUseSaturdayHoliday)
            {
                return true;
            }

            if (plannDueDate.DayOfWeek == DayOfWeek.Sunday && isUseSundayHoliday)
            {
                return true;
            }

            // 휴무일에 포함되어 있는 경우 리턴
            foreach (var item in holidayList)
            {
                if (item.Month == plannDueDate.Month && item.Day == plannDueDate.Day)
                {
                    return true;
                }
            }
            return false;
        }

        private List<DateTime> GetHolidayList(int siteId)
        {
            List<DateTime> holidayList = new List<DateTime>();

            var cmHolidays = db.CmHoliday
                .Where(h => h.SiteId == siteId && h.IsUse == true)
                .ToList();

            int currentYear = DateTime.Now.Year;

            foreach (var item in cmHolidays)
            {
                if (item.IsLunar)
                {
                    Solar sol = new Solar()
                    {
                        solarYear = currentYear,
                        solarMonth = item.HolidayMonth,
                        solarDay = item.HolidayDay
                    };
                    Lunar lun = LunarSolarConverter.SolarToLunar(sol);

                    DateTime date = new DateTime(lun.lunarYear, lun.lunarMonth, lun.lunarDay);
                    holidayList.Add(date);
                }
                else
                {
                    DateTime date = new DateTime(currentYear, item.HolidayMonth, item.HolidayDay);
                    holidayList.Add(date);
                }
            }

            // 커스텀 휴일 리스트
            var customHolidays = db.CmHolidayCustom
                .Where(ch => ch.SiteId == siteId
                    && ch.HolidayDate >= DateTime.Now
                    && ch.IsUse == true)
                .ToList();

            foreach (var item in customHolidays)
            {
                holidayList.Add(item.HolidayDate);
            }
            return holidayList;
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                db.Dispose();
            }
            base.Dispose(disposing);
        }
    }

    public class AvailableDueDateType
    {
        public DateTime DueDate { get; set; }
    }
}