using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;

using FMSAdmin.Data;
using FMSAdmin.Helpers;
using FMSAdmin.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using FMSAdmin.Models;
using System.Transactions;
using FMSApp.Repositories;
using System.Dynamic;

namespace FMSApp.Services {
    public class WorkResultService {
        private readonly ILogger<WorkResultService> _logger;
        private readonly FMSContext _context;

        private readonly AppSettings _appSettings;
        private readonly StorageHelper _storage;

        private readonly WorkRequestRepository _workRequestRepository;
        private readonly HolidayRepository _holidayRepository;

        public WorkResultService(
            ILogger<WorkResultService> logger,
            FMSContext context,
            IOptions<AppSettings> appSettings,
            StorageHelper storage,
            WorkRequestRepository workRequestRepository,
            HolidayRepository holidayRepository
            ) {
            _logger = logger;
            _context = context;
            _appSettings = appSettings.Value;
            _storage = storage;
            _workRequestRepository = workRequestRepository;
            _holidayRepository = holidayRepository;
        }

        // 저장 (사용안함, 작업진행관리의 작업지시내용은 변경 불가능)
        // PC_작업대기 화면 미사용시 시작일과 종료일이 동일하게 들어가기때문에 종료일을 수정하여야 한다. 
        public void Save(FmsWorkResult data) {
            using (var trans = new TransactionScope()) {
                var persist = _context.FmsWorkResult.FirstOrDefault(
                    x => x.SiteId == data.SiteId
                    && x.WorkRequestId == data.WorkRequestId
                );

                if (persist == null) throw new ServiceException("존재하지 않는 데이터 입니다.");

                persist.EndDate = data.EndDate;

                _context.FmsWorkResult.Update(persist);
                _context.SaveChanges();

                trans.Complete();
            }
        }

        // 작업이력 저장
        // 작업이력 저장시 완료/보류 선택여부에 따라 완료 혹은 보류 처리됨.
        public void SaveCheckItem(FmsWorkResultCheckItem data, string userId) {
            using (var trans = new TransactionScope()) {
                var persist = _context.FmsWorkResultCheckItem.FirstOrDefault(
                    x => x.SiteId == data.SiteId
                    && x.WorkRequestId == data.WorkRequestId
                    && x.CheckItemId == data.CheckItemId
                );

                if (persist == null) {
                    // create
                    // 파일 카테고리 및 등록일 설정
                    if (data.CmFile1 != null && data.CmFile1.IsUpload) {
                        data.CmFile1.SiteId = data.SiteId;
                        var category = _context.CmFileCategory.First(x => x.Name == "work");
                        data.CmFile1.FileCategory = category;
                        data.CmFile1.CreatedDate = DateTime.Now;
                    } else {
                        data.CmFile1 = null;
                    }
                    if (data.CmFile2 != null && data.CmFile2.IsUpload) {
                        data.CmFile2.SiteId = data.SiteId;
                        var category = _context.CmFileCategory.First(x => x.Name == "work");
                        data.CmFile2.FileCategory = category;
                        data.CmFile2.CreatedDate = DateTime.Now;
                    } else {
                        data.CmFile2 = null;
                    }

                    // 자재 기본정보 생성되지 않도록 처리
                    foreach (var material in data.FmsWorkResultCheckItemMaterial) {
                        material.FmsMaterial = null;
                        material.FmsWorkResult = null;
                    }

                    _context.FmsWorkResultCheckItem.Add(data);
                    _context.SaveChanges();

                    // 파일 저장
                    if (data.CmFile1 != null && data.CmFile1.IsUpload) {
                        _storage.CopyEntity(data.CmFile1.Path, data.CmFile1);
                    }
                    if (data.CmFile2 != null && data.CmFile2.IsUpload) {
                        _storage.CopyEntity(data.CmFile2.Path, data.CmFile2);
                    }

                    // 출고
                    persist = _context.FmsWorkResultCheckItem.FirstOrDefault(
                        x => x.SiteId == data.SiteId
                        && x.WorkRequestId == data.WorkRequestId
                        && x.CheckItemId == data.CheckItemId
                    );
                    var request = _context.FmsWorkRequest.FirstOrDefault(
                        x => x.SiteId == data.SiteId
                        && x.WorkRequestId == data.WorkRequestId
                    );
                    foreach (var material in persist.FmsWorkResultCheckItemMaterial) {
                        MaterialRelease(material, request, userId);
                    }

                } else {
                    // update
                    // 파일 삭제 / 생성
                    if (data.CmFile1 != null && data.CmFile1.IsUpload) {
                        var category = _context.CmFileCategory.First(x => x.Name == "work");
                        persist.CmFile1 = new CmFile {
                            SiteId = data.SiteId,
                            FileCategory = category,
                            CreatedDate = DateTime.Now,
                            Name = data.CmFile1.Name,
                            FileSize = data.CmFile1.FileSize,
                            ContentType = data.CmFile1.ContentType,
                        };
                        _logger.LogInformation("upload file1");
                    } else if (data.CmFile1 != null && data.CmFile1.IsDelete) {
                        persist.FileId1 = null;
                        persist.CmFile1 = null;
                        _logger.LogInformation("delete file1");
                    }
                    if (data.CmFile2 != null && data.CmFile2.IsUpload) {
                        var category = _context.CmFileCategory.First(x => x.Name == "work");
                        persist.CmFile2 = new CmFile {
                            SiteId = data.SiteId,
                            FileCategory = category,
                            CreatedDate = DateTime.Now,
                            Name = data.CmFile2.Name,
                            FileSize = data.CmFile2.FileSize,
                            ContentType = data.CmFile2.ContentType,
                        };
                        _logger.LogInformation("upload file1");
                    } else if (data.CmFile2 != null && data.CmFile2.IsDelete) {
                        persist.FileId2 = null;
                        persist.CmFile2 = null;
                        _logger.LogInformation("delete file2");
                    }

                    persist.CheckDate = data.CheckDate;
                    persist.TextResult = data.TextResult;

                    _context.FmsWorkResultCheckItem.Update(persist);
                    _context.SaveChanges();

                    // 등록된 전체 자재 목록 삭제
                    foreach (var material in persist.FmsWorkResultCheckItemMaterial.ToList()) {
                        RemoveMaterialRelease(material);
                        _context.FmsWorkResultCheckItemMaterial.Remove(material);
                    }
                    persist.FmsWorkResultCheckItemMaterial.Clear();
                    _context.FmsWorkResultCheckItem.Update(persist);
                    _context.SaveChanges();

                    // 삭제된 아이템 제외하고 신규저장
                    foreach (var material in data.FmsWorkResultCheckItemMaterial) {
                        var createdItem = _context.FmsWorkResultCheckItemMaterial.Add(new FmsWorkResultCheckItemMaterial() {
                            SiteId = persist.SiteId,
                            WorkRequestId = persist.WorkRequestId,
                            CheckItemId = persist.CheckItemId,
                            MaterialId = material.MaterialId,
                            MaterialCode = material.MaterialCode,
                            MaterialCount = material.MaterialCount,
                            Name = material.Name,
                        });
                        _context.SaveChanges();

                        MaterialRelease(createdItem.Entity, persist.FmsWorkResult.FmsWorkRequest, userId);
                    }

                    // 파일 저장
                    if (data.CmFile1 != null && data.CmFile1.IsUpload) {
                        // 카피
                        _storage.CopyEntity(data.CmFile1.Path, persist.CmFile1);
                        if (persist.CmFile1 != null) {
                            // 파일 삭제시 진짜 DB삭제?
                        }
                    }
                    if (data.CmFile2 != null && data.CmFile2.IsUpload) {
                        // 카피
                        _storage.CopyEntity(data.CmFile2.Path, persist.CmFile2);
                        if (persist.CmFile2 != null) {
                            // 파일 삭제시 진짜 DB삭제?
                        }
                    }

                    // 완료된작업의 이력 수정시 날짜가 작업의 종료일자보다 크면 종료일자 업데이트
                    var result = persist.FmsWorkResult;
                    var request = result?.FmsWorkRequest;
                    if (result != null && request != null && request.WorkProgressId == 5) {
                        if (result.EndDate.Date < data.CheckDate.Date) {
                            result.EndDate = data.CheckDate.Date;
                            _context.FmsWorkResult.Update(result);
                            _context.SaveChanges();
                        }
                    }
                }

                //작업 이력 저장시 완료 및 보류 여부 제거에 따른 주석 
                //this.Process(data.SiteId, data.WorkRequestId, data.IsComplete, data.IsHold, data.CheckDate);

                trans.Complete();
            }
        }

        // 완료 / 보류 처리
        // 작업이력 저장 시 사용됨.
        public void Process(int siteId, int workRequestId, bool isComplete, bool isHold, DateTime checkDate) {
            if (!isComplete && !isHold) return;

            var result = _context.FmsWorkResult.FirstOrDefault(
                x => x.SiteId == siteId
                && x.WorkRequestId == workRequestId
            );
            if (result == null) throw new ServiceException("존재하지 않는 데이터 입니다.");

            // 완료 / 보류 처리
            var request = result.FmsWorkRequest;
            if (request == null) throw new ServiceException("존재하지 않는 데이터 입니다.");
            if (request.WorkProgressId == 5 || request.WorkProgressId == 7) {
                return;
            }
            if (request.WorkProgressId != 4) {
                throw new ServiceException("진행상태의 작업이 아닙니다.");
            }

            if (isHold) {
                request.WorkProgressId = 7;
            } else if (isComplete) {
                request.WorkProgressId = 5;
            }

            _context.FmsWorkRequest.Update(request);
            _context.SaveChanges();

            // 완료시 EndDate Update
            if (request.WorkProgressId == 5) {
                result.EndDate = checkDate;
                _context.FmsWorkResult.Update(result);
                _context.SaveChanges();
            }

        }

        // 작업진행 (보류해제)
        public void Continue(FmsWorkResult data) {
            using (var trans = new TransactionScope()) {
                var persist = _context.FmsWorkResult.FirstOrDefault(
                    x => x.SiteId == data.SiteId
                    && x.WorkRequestId == data.WorkRequestId
                );
                if (persist == null) throw new Exception("존재하지 않는 데이터 입니다.");
                if (persist.FmsWorkRequest.WorkProgressId != 7) {
                    throw new ServiceException("보류상태의 작업이 아닙니다.");
                }

                persist.FmsWorkRequest.WorkProgressId = 4;
                _context.FmsWorkRequest.Update(persist.FmsWorkRequest);
                _context.SaveChanges();
                trans.Complete();
            }
        }

        public void CompleteWithAdditionalData(FmsWorkResult data) {
            using (var trans = new TransactionScope()) {
                var request = _context.FmsWorkRequest.FirstOrDefault(
                    x => x.SiteId == data.SiteId
                    && x.WorkRequestId == data.WorkRequestId
                );
                if (request == null) throw new ServiceException("존재하지 않는 데이터 입니다.");

                var result = request.FmsWorkResult;
                if (result == null) throw new ServiceException("존재하지 않는 데이터 입니다.");

                var order = _context.FmsWorkOrder.FirstOrDefault(
                    x => x.SiteId == data.SiteId
                    && x.WorkRequestId == data.WorkRequestId
                );
                if (order == null) throw new Exception("존재하지 않는 데이터 입니다.");

                if (request.WorkProgressId != 4) {
                    throw new ServiceException("진행상태의 작업이 아닙니다.");
                }

                // 추가정보 저장 (작업자, 업체)
                request.WorkUsers = data.FmsWorkRequest.WorkUsers;
                request.WorkPartnerId = data.FmsWorkRequest.WorkPartnerId;
                _context.FmsWorkRequest.Update(request);
                _context.SaveChanges();

                // 추가정보 저장 (시작일, 종료일)
                result.StartDate = data.StartDate;
                result.EndDate = data.EndDate;
                _context.FmsWorkResult.Update(result);
                _context.SaveChanges();

                // 등록된 이력의 CheckDate 중 가장 큰 일자가 Result.EndDate 보다 크면 Result.EndDate Update
                /*
                var checkItem = result.FmsWorkResultCheckItem.OrderByDescending(x => x.CheckDate).FirstOrDefault();
                if (checkItem != null) {
                    if (checkItem.CheckDate.Date > result.EndDate.Date) {
                        result.EndDate = checkItem.CheckDate.Date;
                        _context.FmsWorkResult.Update(result);
                        _context.SaveChanges();
                    }
                } else {
                    if (result.StartDate.Date < DateTime.Now.Date) {
                        result.EndDate = DateTime.Now.Date;
                        _context.FmsWorkResult.Update(result);
                        _context.SaveChanges();
                    }
                }
                */

                request.WorkProgressId = 5;
                _context.FmsWorkRequest.Update(request);
                _context.SaveChanges();

                trans.Complete();
            }
        }

        public void Complete(FmsWorkRequest data) {
            using (var trans = new TransactionScope()) {
                var request = _context.FmsWorkRequest.FirstOrDefault(
                    x => x.SiteId == data.SiteId
                    && x.WorkRequestId == data.WorkRequestId
                );
                if (request == null) throw new ServiceException("존재하지 않는 데이터 입니다.");
                if (request.WorkProgressId != 4) {
                    throw new ServiceException("진행상태의 작업이 아닙니다.");
                }

                // 등록된 이력의 CheckDate 중 가장 큰 일자가 Result.EndDate 보다 크면 Result.EndDate Update
                var result = request.FmsWorkResult;
                if (result == null) throw new ServiceException("존재하지 않는 데이터 입니다.");
                var checkItem = result.FmsWorkResultCheckItem.OrderByDescending(x => x.CheckDate).FirstOrDefault();
                if (checkItem != null) {
                    if (checkItem.CheckDate.Date > result.EndDate.Date) {
                        result.EndDate = checkItem.CheckDate.Date;
                        _context.FmsWorkResult.Update(result);
                        _context.SaveChanges();
                    }
                } else {
                    if (result.StartDate.Date < DateTime.Now.Date) {
                        result.EndDate = DateTime.Now.Date;
                        _context.FmsWorkResult.Update(result);
                        _context.SaveChanges();
                    }
                }

                request.WorkProgressId = 5;
                _context.FmsWorkRequest.Update(request);
                _context.SaveChanges();

                trans.Complete();
            }
        }

        public void Hold(FmsWorkRequest data) {
            using (var trans = new TransactionScope()) {
                var request = _context.FmsWorkRequest.FirstOrDefault(
                    x => x.SiteId == data.SiteId
                    && x.WorkRequestId == data.WorkRequestId
                );
                if (request == null) throw new Exception("존재하지 않는 데이터 입니다.");
                if (request.WorkProgressId != 4) {
                    throw new ServiceException("진행상태의 작업이 아닙니다.");
                }

                request.WorkProgressId = 7;
                _context.FmsWorkRequest.Update(request);
                _context.SaveChanges();
                trans.Complete();
            }
        }

        // 작업승인
        public void Confirm(FmsWorkResult data, DateTime? date) {
            using (var trans = new TransactionScope()) {
                var result = _context.FmsWorkResult.FirstOrDefault(
                    x => x.SiteId == data.SiteId
                    && x.WorkRequestId == data.WorkRequestId
                );
                if (result == null) throw new Exception("존재하지 않는 데이터 입니다.");

                var request = _context.FmsWorkRequest.FirstOrDefault(
                    x => x.SiteId == data.SiteId
                    && x.WorkRequestId == data.WorkRequestId
                );
                if (request == null) throw new Exception("존재하지 않는 데이터 입니다.");

                var order = _context.FmsWorkOrder.FirstOrDefault(
                    x => x.SiteId == data.SiteId
                    && x.WorkRequestId == data.WorkRequestId
                );
                if (order == null) throw new Exception("존재하지 않는 데이터 입니다.");

                if (request.WorkProgressId != 5) {
                    throw new ServiceException("작업완료상태의 데이터만 승인 가능합니다.");
                }

                // save request
                request.Content = data.FmsWorkRequest.Content;
                request.WorkProgressId = 6;

                _context.FmsWorkRequest.Update(request);
                _context.SaveChanges();

                // save order
                order.Content = data.FmsWorkOrder.Content;
                _context.FmsWorkOrder.Update(order);
                _context.SaveChanges();

                // save result
                result.Content = data.Content;
                result.ConfirmDesc = data.ConfirmDesc;
                result.ConfirmedUserId = data.ConfirmedUserId;
                result.ConfirmedDate = DateTime.Now;
                result.IsConfirmed = true;
                _context.FmsWorkResult.Update(result);
                _context.SaveChanges();

                // 차기 작업 생성
                if (request.FmsWorkSchedule != null && !request.FmsWorkSchedule.IsNotProcess) {
                    if (date == null) {
                        throw new ServiceException("차기작업 확정일자가 선택되지 않았습니다.");
                    }
                    var schedule = _context.FmsWorkSchedule.FirstOrDefault(
                        x => x.SiteId == data.SiteId
                        && x.WorkScheduleId == request.WorkScheduleId
                    );

                    // 다음 계획일 업데이트
                    schedule.WorkDueDate = date.Value.Date;
                    _context.FmsWorkSchedule.Update(schedule);
                    _context.SaveChanges();

                    // 작업계획 생성
                    if (!_workRequestRepository.IsCreatedRequest(schedule)) {
                        _workRequestRepository.CreateFromWorkSchedule(schedule);
                    }
                }

                trans.Complete();
            }
        }

        // 작업승인 및 추가정보 저장
        public void ConfirmWithAdditionalData(FmsWorkResult data, DateTime? date) {
            using (var trans = new TransactionScope()) {
                var result = _context.FmsWorkResult.FirstOrDefault(
                    x => x.SiteId == data.SiteId
                    && x.WorkRequestId == data.WorkRequestId
                );
                if (result == null) throw new Exception("존재하지 않는 데이터 입니다.");

                var request = _context.FmsWorkRequest.FirstOrDefault(
                    x => x.SiteId == data.SiteId
                    && x.WorkRequestId == data.WorkRequestId
                );
                if (request == null) throw new Exception("존재하지 않는 데이터 입니다.");

                var order = _context.FmsWorkOrder.FirstOrDefault(
                    x => x.SiteId == data.SiteId
                    && x.WorkRequestId == data.WorkRequestId
                );
                if (order == null) throw new Exception("존재하지 않는 데이터 입니다.");

                if (request.WorkProgressId != 5) {
                    throw new ServiceException("작업완료상태의 데이터만 승인 가능합니다.");
                }

                // save request
                request.Content = data.FmsWorkRequest.Content;
                request.WorkProgressId = 6;
                request.WorkUsers = data.FmsWorkRequest.WorkUsers;
                request.WorkDate = data.FmsWorkRequest.WorkDate;
                request.WorkPartnerId = data.FmsWorkRequest.WorkPartnerId;

                _context.FmsWorkRequest.Update(request);
                _context.SaveChanges();

                // save order
                order.Content = data.FmsWorkOrder.Content;
                _context.FmsWorkOrder.Update(order);
                _context.SaveChanges();

                // save result
                result.Content = data.Content;
                result.StartDate = data.StartDate;
                result.EndDate = data.EndDate;
                result.ConfirmDesc = data.ConfirmDesc;
                result.ConfirmedUserId = data.ConfirmedUserId;
                result.ConfirmedDate = DateTime.Now;
                result.IsConfirmed = true;
                _context.FmsWorkResult.Update(result);
                _context.SaveChanges();

                // 차기 작업 생성
                if (request.FmsWorkSchedule != null && !request.FmsWorkSchedule.IsNotProcess) {
                    if (date == null) {
                        throw new ServiceException("차기작업 확정일자가 선택되지 않았습니다.");
                    }
                    var schedule = _context.FmsWorkSchedule.FirstOrDefault(
                        x => x.SiteId == data.SiteId
                        && x.WorkScheduleId == request.WorkScheduleId
                    );

                    // 다음 계획일 업데이트
                    schedule.WorkDueDate = date.Value.Date;
                    _context.FmsWorkSchedule.Update(schedule);
                    _context.SaveChanges();

                    // 작업계획 생성
                    if (!_workRequestRepository.IsCreatedRequest(schedule)) {
                        _workRequestRepository.CreateFromWorkSchedule(schedule);
                    }
                }

                trans.Complete();
            }
        }

        // 자재출고
        public void MaterialRelease(FmsWorkResultCheckItemMaterial item, FmsWorkRequest request, string confirmedUserId) {
            var material = _context.FmsMaterial.FirstOrDefault(
                x => x.SiteId == item.SiteId
                && x.MaterialId == item.MaterialId
            );
            if (material == null) return;

            var release = new FmsMaterialRelease() {
                SiteId = item.SiteId,
                BusinessFieldId = request.BusinessFieldId,
                ReleaseDate = DateTime.Now,
                ReleaseTypeId = 1, // 작업출고
                WorkRequestId = request.WorkRequestId,
                CheckItemMaterialId = item.CheckItemMaterialId,
                MaterialId = item.MaterialId,
                MaterialCount = item.MaterialCount,
                ReleaseTotalCost = 0,
                ConfirmedUserId = confirmedUserId,
                ConfirmedDate = DateTime.Now,
                IsConfirmed = true,
                AdjustmentTypeId = 0,
            };

            // 선입선출에 따른 계산 (입고된 자재중 오래된 입고자재의 단가를 먼저 가져온다.)
            var storedList = material.FmsMaterialStored.Where(
                x => x.IsApproval == true
                && x.RemainStoredCount > 0
            ).OrderBy(x => x.StoredDate).ToList();

            var tempReleasedItemCount = item.MaterialCount;

            foreach (var storedItem in storedList) {
                if ((storedItem.RemainStoredCount - tempReleasedItemCount) >= 0) {
                    release.ReleaseTotalCost += (storedItem.UnitCost * tempReleasedItemCount);
                    storedItem.RemainStoredCount -= tempReleasedItemCount;
                    release.FmsMaterialReleaseDetail.Add(new FmsMaterialReleaseDetail() {
                        SiteId = storedItem.SiteId,
                        MaterialStoredId = storedItem.MaterialStoredId,
                        MaterialCount = tempReleasedItemCount,
                    });
                    tempReleasedItemCount = 0;
                    break;
                }

                release.ReleaseTotalCost += (storedItem.UnitCost * storedItem.RemainStoredCount);
                tempReleasedItemCount -= storedItem.RemainStoredCount;
                release.FmsMaterialReleaseDetail.Add(new FmsMaterialReleaseDetail() {
                    SiteId = storedItem.SiteId,
                    MaterialStoredId = storedItem.MaterialStoredId,
                    MaterialCount = storedItem.RemainStoredCount,
                });
                storedItem.RemainStoredCount = 0;
            }
            if (tempReleasedItemCount > 0) {
                throw new ServiceException(item.FmsMaterial.Name + " 자재의 입고수량이 부족하여 출고처리가 불가능합니다.");
            }

            _context.FmsMaterialRelease.Add(release);
            _context.SaveChanges();
        }

        // 자재 출고 삭제
        public void RemoveMaterialRelease(FmsWorkResultCheckItemMaterial item) {
            var releaseList = _context.FmsMaterialRelease.Where(
                x => x.MaterialId == item.MaterialId
                && x.WorkRequestId == item.WorkRequestId
                && x.CheckItemMaterialId == item.CheckItemMaterialId
            ).ToList();

            foreach (var release in releaseList) {
                foreach (var detail in release.FmsMaterialReleaseDetail) {
                    // 차감 수량 되돌림
                    var stored = detail.FmsMaterialStored;
                    stored.RemainStoredCount += detail.MaterialCount;
                    _context.FmsMaterialStored.Update(stored);

                    // 디테일 삭제
                    _context.FmsMaterialReleaseDetail.Remove(detail);
                }

                // 출고 삭제
                _context.FmsMaterialRelease.Remove(release);
            }

            _context.SaveChanges();
        }

        // 차기작업 확정일자 및 현작업 종료일, 작업계획사용여부 조회
        public dynamic GetAvailDueDate(int siteId, int workRequestId) {
            DateTime WorkDueDate = DateTime.Now.Date;
            DateTime EndDate = DateTime.Now.Date;

            var result = _context.FmsWorkResult.FirstOrDefault(
                x => x.SiteId == siteId
                && x.WorkRequestId == workRequestId
            );
            if (result == null) return new { WorkDueDate, EndDate, IsUse = false };
            EndDate = result.EndDate.Date;

            var request = _context.FmsWorkRequest.FirstOrDefault(
                x => x.SiteId == siteId
                && x.WorkRequestId == workRequestId
            );
            if (request == null) return new { WorkDueDate, EndDate, IsUse = false };

            var schedule = _context.FmsWorkSchedule.FirstOrDefault(
                x => x.SiteId == siteId
                && x.WorkScheduleId == request.WorkScheduleId
            );
            if (schedule == null) return new { WorkDueDate, EndDate, IsUse = false };

            switch (schedule.CycleUnitId) {
                case 1: WorkDueDate = EndDate.AddDays(schedule.CycleSize); break;
                case 2: WorkDueDate = EndDate.AddDays(schedule.CycleSize * 7); break;
                case 3: WorkDueDate = EndDate.AddMonths(schedule.CycleSize); break;
                case 4: WorkDueDate = EndDate.AddMonths(schedule.CycleSize * 3); break;
                case 5: WorkDueDate = EndDate.AddMonths(schedule.CycleSize * 6); break;
                case 6: WorkDueDate = EndDate.AddYears(schedule.CycleSize); break;
            }

            if (schedule.HolidayWorkTypeId == 0) return new { WorkDueDate, EndDate, IsUse = schedule.IsUse };

            var weekend = _holidayRepository.GetHolidayWeekend(siteId);
            var holidays = _holidayRepository.GetHolidays(siteId);

            bool isHoliday = _holidayRepository.IsHoliday(WorkDueDate, weekend, holidays);
            if (schedule.HolidayWorkTypeId == 1) {
                while (!isHoliday) {
                    WorkDueDate = WorkDueDate.AddDays(1);
                    isHoliday = _holidayRepository.IsHoliday(WorkDueDate, weekend, holidays);
                }
                return new { WorkDueDate, EndDate, IsUse = schedule.IsUse };
            }
            if (schedule.HolidayWorkTypeId == 2) {
                while (isHoliday) {
                    WorkDueDate = WorkDueDate.AddDays(1);
                    isHoliday = _holidayRepository.IsHoliday(WorkDueDate, weekend, holidays);
                }
                return new { WorkDueDate, EndDate, IsUse = schedule.IsUse };
            }
            return new { WorkDueDate, EndDate, IsUse = schedule.IsUse };
        }

        public void Delete(int siteId, int workRequestId) {

            using (var trans = new TransactionScope()) {
                var checkItemMaterials = _context.FmsWorkResultCheckItemMaterial.Where(
                    x => x.SiteId == siteId
                    && x.WorkRequestId == workRequestId
                ).ToList();
                foreach (var item in checkItemMaterials) {
                    RemoveMaterialRelease(item);
                    _context.FmsWorkResultCheckItemMaterial.Remove(item);
                }
                _context.SaveChanges();

                var releases = _context.FmsMaterialRelease.Where(
                    x => x.SiteId == siteId
                    && x.WorkRequestId == workRequestId
                ).ToList();
                foreach (var release in releases) {
                    var details = _context.FmsMaterialReleaseDetail.Where(
                        x => x.MaterialReleaseId == release.MaterialReleaseId
                    ).ToList();
                    foreach (var detail in details) {
                        _context.FmsMaterialReleaseDetail.Remove(detail);
                    }
                    _context.FmsMaterialRelease.Remove(release);
                }
                _context.SaveChanges();

                var checkItems = _context.FmsWorkResultCheckItem.Where(
                    x => x.SiteId == siteId
                    && x.WorkRequestId == workRequestId
                ).ToList();
                foreach (var item in checkItems) {
                    _context.FmsWorkResultCheckItem.Remove(item);
                }
                _context.SaveChanges();

                var workResultToFacilities = _context.FmsWorkResultToFacility.Where(
                    x => x.SiteId == siteId
                    && x.WorkRequestId == workRequestId
                ).ToList();
                foreach (var item in workResultToFacilities) {
                    _context.FmsWorkResultToFacility.Remove(item);
                }
                _context.SaveChanges();

                var workResult = _context.FmsWorkResult.Where(
                    x => x.SiteId == siteId
                    && x.WorkRequestId == workRequestId
                ).ToList();
                foreach (var item in workResult) {
                    _context.FmsWorkResult.Remove(item);
                }
                _context.SaveChanges();

                var workOrderToFacilities = _context.FmsWorkOrderToFacility.Where(
                    x => x.SiteId == siteId
                    && x.WorkRequestId == workRequestId
                ).ToList();
                foreach (var item in workOrderToFacilities) {
                    _context.FmsWorkOrderToFacility.Remove(item);
                }
                _context.SaveChanges();

                var workOrder = _context.FmsWorkOrder.Where(
                    x => x.SiteId == siteId
                    && x.WorkRequestId == workRequestId
                ).ToList();
                foreach (var item in workOrder) {
                    _context.FmsWorkOrder.Remove(item);
                }
                _context.SaveChanges();

                var workRequestToFacilities = _context.FmsWorkRequestToFacility.Where(
                    x => x.SiteId == siteId
                    && x.WorkRequestId == workRequestId
                ).ToList();
                foreach (var item in workRequestToFacilities) {
                    _context.FmsWorkRequestToFacility.Remove(item);
                }
                _context.SaveChanges();

                var workRequestToAccidents = _context.FmsWorkRequestToAccident.Where(
                    x => x.SiteId == siteId
                    && x.WorkRequestId == workRequestId
                ).ToList();
                foreach (var item in workRequestToAccidents) {
                    _context.FmsWorkRequestToAccident.Remove(item);
                }
                _context.SaveChanges();

                var workRequestToComplaints = _context.FmsWorkRequestToComplaint.Where(
                    x => x.SiteId == siteId
                    && x.WorkRequestId == workRequestId
                ).ToList();
                foreach (var item in workRequestToComplaints) {
                    _context.FmsWorkRequestToComplaint.Remove(item);
                }
                _context.SaveChanges();

                var workRequest = _context.FmsWorkRequest.FirstOrDefault(
                    x => x.SiteId == siteId
                    && x.WorkRequestId == workRequestId
                );
                var workSchedule = workRequest.FmsWorkSchedule;
                _context.FmsWorkRequest.Remove(workRequest);
                _context.SaveChanges();

                if (workSchedule != null && workSchedule.IsNotProcess) {
                    var requestCount = _context.FmsWorkRequest.Count(x => x.SiteId == siteId && x.WorkScheduleId == workSchedule.WorkScheduleId);
                    if (requestCount <= 0) {
                        foreach (var facility in workSchedule.FmsWorkScheduleToFacility.ToList()) {
                            _context.FmsWorkScheduleToFacility.Remove(facility);
                        }
                        _context.FmsWorkSchedule.Remove(workSchedule);
                        _context.SaveChanges();
                    }
                }

                trans.Complete();
            }

            // 차기작업 생성 않해도 되나?
        }

        public IQueryable<FmsWorkResult> GetAll() {
            var query = _context.FmsWorkResult;
            return query;
        }

        public IQueryable<CalendarEvent> GetRequestResult(int? siteId, DateTime startDate, DateTime endDate) {
            var query = (from x in _context.FmsWorkRequest
                         where x.SiteId == (siteId != null ? siteId : x.SiteId)
                         where x.StartWorkDate.Date >= startDate.Date
                         where x.StartWorkDate.Date <= endDate.Date
                         group x by x.StartWorkDate.Date into g
                         select new {
                             WorkDate = g.Key,
                             Count = g.Count(),
                             ConfirmCount = 0,
                         }).Concat(
                             from x in _context.FmsWorkResult
                             where x.SiteId == (siteId != null ? siteId : x.SiteId)
                             where x.FmsWorkRequest.StartWorkDate.Date >= startDate.Date
                             where x.FmsWorkRequest.StartWorkDate.Date <= endDate.Date
                             where x.FmsWorkRequest.WorkProgressId == 6
                             group x by x.FmsWorkRequest.StartWorkDate.Date into g
                             select new {
                                 WorkDate = g.Key,
                                 Count = 0,
                                 ConfirmCount = g.Count(),
                             }
                         );

            var query2 = from x in query
                         group x by x.WorkDate into g
                         select new CalendarEvent {
                             Title = "계획 : " + g.Sum(x => x.Count).ToString("#,##0") + " 건 / 완료 : " + g.Sum(x => x.ConfirmCount).ToString("#,##0") + " 건",
                             RequestCount = g.Sum(x => x.Count),
                             ConfirmCount = g.Sum(x => x.ConfirmCount),
                             Start = g.Key.ToString("yyyy-MM-dd"),
                             End = g.Key.ToString("yyyy-MM-dd"),
                             WorkType = "계획_완료",
                             GroupId = 3,
                             Id = g.Key.ToString("yyyy-MM-dd"),
                         };

            return query2;
        }

        public IQueryable<FmsWorkRequest> GetCustomRequestResultList(int? siteId, DateTime startDate, DateTime endDate) {
            var query = _context.FmsWorkRequest.Where(x =>
                x.SiteId == (siteId != null ? siteId : x.SiteId) &&
                x.StartWorkDate.Date >= startDate.Date &&
                x.StartWorkDate.Date <= endDate.Date);

            return query;
        }
    }
}