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 FMSApp.Repositories;
using System.Transactions;

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

        private readonly AppSettings _appSettings;
        private readonly StorageHelper _storage;

        private readonly WorkRequestRepository _workRequestRepository;
        private readonly WorkConfigRepository _workConfigRepository;

        public WorkScheduleService(
            ILogger<WorkScheduleService> logger,
            FMSContext context,
            IOptions<AppSettings> appSettings,
            StorageHelper storage,
            WorkRequestRepository workRequestRepository,
            WorkConfigRepository workConfigRepository
            ) {
            _logger = logger;
            _context = context;
            _appSettings = appSettings.Value;
            _storage = storage;
            _workRequestRepository = workRequestRepository;
            _workConfigRepository = workConfigRepository;
        }

        // 작업스케쥴 저장 (정기점검, 법정검사, 법정교육 저장)
        public void Save(FmsWorkSchedule data) {
            FmsWorkSchedule schedule = null;

            using (var trans = new TransactionScope()) {
                var persist = _context.FmsWorkSchedule
                                .Where(x => x.SiteId == data.SiteId
                                    && x.WorkScheduleId == data.WorkScheduleId).FirstOrDefault();
                if (persist == null) {
                    var check = _context.FmsWorkSchedule.Where(x => x.SiteId == data.SiteId
                        && x.BusinessFieldId == data.BusinessFieldId
                        && x.Name == data.Name).Count();
                    if (check > 0) {
                        throw new ServiceException("동일한 작업계획이 이미 등록되어있습니다.(등록)");
                    }

                    // 법정교육일때 설비목록 제거
                    if (data.WorkTypeId == 7) {
                        data.FmsWorkScheduleToFacility = new List<FmsWorkScheduleToFacility>();
                    }

                    // 설비 기본정보 생성되지 않도록 처리
                    foreach (var facility in data.FmsWorkScheduleToFacility) {
                        facility.CmFacility = null;
                    }

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

                    schedule = data;

                    // 등록시에는 Request 자동 생성
                    _workRequestRepository.CreateFromWorkSchedule(schedule);
                } else {
                    var check = _context.FmsWorkSchedule.Where(x => x.SiteId == data.SiteId
                        && x.WorkScheduleId != data.WorkScheduleId
                        && x.BusinessFieldId == data.BusinessFieldId
                        && x.Name == data.Name).Count();
                    if (check > 0) {
                        throw new ServiceException("동일한 작업계획이 이미 등록되어있습니다.(수정)");
                    }

                    // 입력 데이터 반영
                    persist.BusinessFieldId = data.BusinessFieldId;
                    persist.Name = data.Name;
                    persist.InspectionAgencyId = data.InspectionAgencyId;
                    persist.CycleSize = data.CycleSize;
                    persist.CycleUnitId = data.CycleUnitId;
                    persist.HolidayWorkTypeId = data.HolidayWorkTypeId;
                    persist.WorkDueDate = data.WorkDueDate.Date;
                    persist.UpdateUserId = data.UpdateUserId;
                    persist.IsUse = data.IsUse;
                    persist.IsAutoOrder = data.IsAutoOrder;
                    persist.Content = data.Content;

                    // 법정교육일때 설비목록 제거
                    if (data.WorkTypeId == 7) {
                        data.FmsWorkScheduleToFacility = new List<FmsWorkScheduleToFacility>();
                    }

                    //등록된 설비 전체 삭제
                    persist.FmsWorkScheduleToFacility.Clear();

                    // 추가된 설비 생성
                    foreach (var facility in data.FmsWorkScheduleToFacility) {
                        persist.FmsWorkScheduleToFacility.Add(new FmsWorkScheduleToFacility() {
                            SiteId = persist.SiteId,
                            WorkScheduleId = persist.WorkScheduleId,
                            FacilityCode = facility.FacilityCode,
                        });
                    }

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

                    schedule = persist;

                    // 수정시에는 해당 Schedule 을 물고있는 Request 중
                    // 작업완료 이전단계(1:작업계획, 3:작업대기, 4:작업진행, 7:작업보류)의 Request, Order, Result 의 정보를 Update 한다.
                    _workRequestRepository.UpdateFromWorkSchedule(schedule);
                }

                trans.Complete();
            }
        }

        public void SaveExpectedRequest(FmsWorkSchedule data) {
            FmsWorkSchedule schedule = null;

            using (var trans = new TransactionScope()) {
                var persist = _context.FmsWorkSchedule
                                .Where(x => x.SiteId == data.SiteId
                                    && x.WorkScheduleId == data.WorkScheduleId).FirstOrDefault();
                if (persist == null) {

                    var check = _context.FmsWorkSchedule.Where(x => x.SiteId == data.SiteId
                        && x.BusinessFieldId == data.BusinessFieldId
                        && x.Name == data.Name
                        && x.WorkDueDate.Date <= data.WorkDueDate.Date && x.WorkExpireDate >= data.WorkDueDate.Date
                    ).Count();

                    if (check > 0) {
                        throw new ServiceException("동일한 작업계획이 이미 등록되어있습니다.(등록)");
                    }

                    // 법정교육일때 설비목록 제거
                    if (data.WorkTypeId == 7) {
                        data.FmsWorkScheduleToFacility = new List<FmsWorkScheduleToFacility>();
                    }

                    // 설비 기본정보 생성되지 않도록 처리
                    foreach (var facility in data.FmsWorkScheduleToFacility) {
                        facility.CmFacility = null;
                    }

                    schedule = data;

                    // 등록시에는 Request 자동 생성
                    _workRequestRepository.CreateAllRequestFromWorkSchedule(schedule);
                }

                trans.Complete();
            }
        }

        public void DeleteWithResult(int siteId, int workRequestId) {
            var request = _context.FmsWorkRequest.First(x => x.SiteId == siteId && x.WorkRequestId == workRequestId);
            var order = request.FmsWorkOrder;
            var result = request.FmsWorkResult;
            var schedule = request.FmsWorkSchedule;

            if (result != null && result.FmsWorkResultCheckItem.Count > 0) {
                throw new ServiceException("진행중인작업은 삭제할수 없습니다.");
            }

            if (result != null) {
                foreach (var facility in result.FmsWorkResultToFacility.ToList()) {
                    _context.FmsWorkResultToFacility.Remove(facility);
                }
                _context.FmsWorkResult.Remove(result);
                _context.SaveChanges();
            }

            if (order != null) {
                foreach (var facility in order.FmsWorkOrderToFacility.ToList()) {
                    _context.FmsWorkOrderToFacility.Remove(facility);
                }
                _context.FmsWorkOrder.Remove(order);
                _context.SaveChanges();
            }

            if (request != null) {
                foreach (var facility in request.FmsWorkRequestToFacility.ToList()) {
                    _context.FmsWorkRequestToFacility.Remove(facility);
                }
                foreach (var accident in request.FmsWorkRequestToAccident.ToList()) {
                    _context.FmsWorkRequestToAccident.Remove(accident);
                }
                foreach (var complaint in request.FmsWorkRequestToComplaint.ToList()) {
                    _context.FmsWorkRequestToComplaint.Remove(complaint);
                }
                _context.FmsWorkRequest.Remove(request);
                _context.SaveChanges();
            }

            if (schedule != null && schedule.IsNotProcess) {
                // 처리되지 않는 작업계획(참고용) 의 경우 모든 Request 가 삭제된 경우 같이 삭제함.
                var requestCount = _context.FmsWorkRequest.Count(x => x.SiteId == schedule.SiteId && x.WorkScheduleId == schedule.WorkScheduleId);
                if (requestCount <= 0) {
                    foreach (var facility in schedule.FmsWorkScheduleToFacility.ToList()) {
                        _context.FmsWorkScheduleToFacility.Remove(facility);
                    }
                    _context.FmsWorkSchedule.Remove(schedule);
                    _context.SaveChanges();
                }
            }
        }

        public void Delete(int siteId, int workScheduleId) {
            var data = _context.FmsWorkSchedule.First(x => x.SiteId == siteId && x.WorkScheduleId == workScheduleId);
            _context.FmsWorkSchedule.Remove(data);

            _context.SaveChanges();
        }

        public string GetUpdateScheduleWarningMessage(int siteId, int workScheduleId) {
            // 작업계획(1) : 메세지 표시.(IsAutoOrder, IsAutoResult 아닐때만)
            // 작업대기(3) : 메세지 표시.(IsAutoOrder, IsAutoResult 아닐때만)
            // 작업진행(4) : 메세지 표시.

            var schedule = _context.FmsWorkSchedule.Where(
                x => x.SiteId == siteId
                && x.WorkScheduleId == workScheduleId
            ).FirstOrDefault();
            if (schedule == null) return null;

            var request = _context.FmsWorkRequest.Where(
                x => x.SiteId == schedule.SiteId
                && x.WorkScheduleId == schedule.WorkScheduleId
                && (new int[] { 1, 3, 4 }).Contains(x.WorkProgressId)
            ).OrderByDescending(x => x.WorkRequestId).FirstOrDefault();
            if (request == null) return null;

            string warningMessage = "해당 계획수정시 진행중인 작업의 내용이 같이 변경됩니다. 변경하시겠습니까?";
            if (request.WorkProgressId == 1 || request.WorkProgressId == 3) {
                if (!_workConfigRepository.IsAutoOrder() || !_workConfigRepository.IsAutoResult()) {
                    return warningMessage;
                }
            } else {
                return warningMessage;
            }

            return null;
        }

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