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;

namespace FMSAdmin.Services {
    public class MaterialReleaseService {
        private readonly ILogger<MaterialReleaseService> _logger;
        private readonly FMSContext _context;
        private readonly StorageHelper _storage;

        public MaterialReleaseService(
            ILogger<MaterialReleaseService> logger,
            FMSContext context,
            StorageHelper storage) {
            _logger = logger;
            _context = context;
            _storage = storage;
        }

        public void Create(FmsMaterialRelease data) {
            using (var transaction = _context.Database.BeginTransaction()) {
                //재고 체크
                foreach (var item in data.MaterialReleaseList) {
                    if (data.AdjustmentTypeId == 1) {
                        if (item.MaterialCount > item.StockCountByPoint) {
                            throw new ServiceException("자재손실은 재고수량 보다 클 수 없습니다.");
                        }
                    } else if (data.AdjustmentTypeId == 2) {
                        int nCnt = 0;
                        var persist = _context.FmsMaterialStored.Where(x => x.SiteId == item.SiteId && x.MaterialId == item.MaterialId).ToList();
                        if (persist == null) {
                            throw new ServiceException("정보를 찾을 수 없습니다.");
                        }

                        foreach (var storedItem in persist) {
                            nCnt += storedItem.StoredCount + storedItem.RemainStoredCount;
                        }

                        if (item.MaterialCount <= nCnt) {
                            item.ReleaseTotalCost = 0;

                            //data.MaterialReleaseList.Add(item);
                        } else {
                            throw new ServiceException("반납할 재고가 없습니다.");
                        }
                    }
                }
                data.ReleaseTypeId = 2;     //조정출고
                data.ReleaseDate = DateTime.Now;

                foreach (var item in data.MaterialReleaseList) {
                    FmsMaterialRelease releaseItem = new FmsMaterialRelease() {
                        SiteId = data.SiteId,
                        BusinessFieldId = data.BusinessFieldId,
                        ReleaseDate = data.ReleaseDate,
                        ReleaseTypeId = data.ReleaseTypeId,
                        MaterialId = item.MaterialId,
                        MaterialCount = item.MaterialCount,
                        IsConfirmed = false,
                        AdjustmentTypeId = data.AdjustmentTypeId,
                        AdjustmentUserId = data.AdjustmentUserId,
                        Comment = data.Comment,
                        ReleaseTotalCost = 0,
                        StockCountByPoint = item.StockCountByPoint,
                    };

                    //선입선출에 따른 계산
                    if (data.AdjustmentTypeId == 1) {       //조정 손실인 경우
                        var currentStoredList = _context.FmsMaterialStored.Where(x => x.IsApproval == true && x.MaterialId == item.MaterialId && x.RemainStoredCount > 0).OrderBy(x => x.StoredDate).ToList();
                        int releaseMaterialCount = item.MaterialCount.Value;

                        foreach (var storedItem in currentStoredList) {
                            if ((storedItem.RemainStoredCount - releaseMaterialCount) >= 0) {
                                releaseItem.ReleaseTotalCost += (storedItem.UnitCost * releaseMaterialCount);
                                storedItem.RemainStoredCount -= releaseMaterialCount;
                                releaseItem.FmsMaterialReleaseDetail.Add(new FmsMaterialReleaseDetail() {
                                    SiteId = data.SiteId,
                                    MaterialStoredId = storedItem.MaterialStoredId,
                                    MaterialCount = releaseMaterialCount,
                                    FmsMaterialStored = storedItem,
                                });
                                _context.FmsMaterialStored.Update(storedItem);
                                releaseMaterialCount = 0;
                                break;
                            }

                            releaseItem.ReleaseTotalCost += (storedItem.UnitCost * storedItem.RemainStoredCount);
                            releaseMaterialCount -= storedItem.RemainStoredCount;
                            releaseItem.FmsMaterialReleaseDetail.Add(new FmsMaterialReleaseDetail() {
                                SiteId = data.SiteId,
                                MaterialStoredId = storedItem.MaterialStoredId,
                                MaterialCount = storedItem.RemainStoredCount,
                            });
                            storedItem.RemainStoredCount = 0;
                            _context.FmsMaterialStored.Update(storedItem);
                        }

                        if (releaseMaterialCount > 0) {
                            throw new ServiceException("자재손실은 재고수량 보다 클 수 없습니다.");
                        }
                    } else if (data.AdjustmentTypeId == 2) {     //조정 반납인 경우
                        var currentStoredList = _context.FmsMaterialStored.Where(x => x.IsApproval == true && x.MaterialId == item.MaterialId && x.StoredCount != x.RemainStoredCount).OrderByDescending(x => x.StoredDate).ToList();
                        int releaseMaterialCount = item.MaterialCount.Value;

                        foreach (var storedItem in currentStoredList) {
                            if ((storedItem.RemainStoredCount + releaseMaterialCount) <= storedItem.StoredCount) {
                                releaseItem.ReleaseTotalCost += (storedItem.UnitCost * releaseMaterialCount);
                                storedItem.RemainStoredCount += releaseMaterialCount;
                                releaseItem.FmsMaterialReleaseDetail.Add(new FmsMaterialReleaseDetail() {
                                    SiteId = data.SiteId,
                                    MaterialStoredId = storedItem.MaterialStoredId,
                                    MaterialCount = releaseMaterialCount * -1,
                                    FmsMaterialStored = storedItem,
                                });
                                _context.FmsMaterialStored.Update(storedItem);
                                break;
                            }

                            var returnItemCount = storedItem.StoredCount - storedItem.RemainStoredCount;

                            releaseItem.ReleaseTotalCost += (storedItem.UnitCost * returnItemCount);
                            releaseMaterialCount -= returnItemCount;
                            storedItem.RemainStoredCount = storedItem.StoredCount;
                            releaseItem.FmsMaterialReleaseDetail.Add(new FmsMaterialReleaseDetail() {
                                SiteId = data.SiteId,
                                MaterialStoredId = storedItem.MaterialStoredId,
                                MaterialCount = storedItem.StoredCount * -1,
                                FmsMaterialStored = storedItem,
                            });
                            _context.FmsMaterialStored.Update(storedItem);
                        }
                    }

                    if (_context.SiteConfig.Single().UseMaterialAdjustmentAutoApproval) {
                        releaseItem.IsConfirmed = true;
                        releaseItem.ConfirmedUserId = data.AdjustmentUserId;
                        releaseItem.ConfirmedDate = DateTime.Now;
                    }

                    _context.FmsMaterialRelease.Add(releaseItem);
                }

                _context.SaveChanges();

                transaction.Commit();
            }
        }

        public void Edit(int id, int siteId, FmsMaterialRelease data) {
            var persist = _context.FmsMaterialRelease
                            .Where(x => x.MaterialReleaseId == id && x.SiteId == siteId).FirstOrDefault();
            if (persist == null) {
                throw new ServiceException("정보를 찾을 수 없습니다.");
            }

            using (var transaction = _context.Database.BeginTransaction()) {
                persist.MaterialCount = data.MaterialReleaseList.Select(x => x.MaterialCount).FirstOrDefault();
                _context.FmsMaterialRelease.Update(persist);
                _context.SaveChanges();

                transaction.Commit();
            }
        }

        public IQueryable<FmsMaterialRelease> GetAll() {
            var query = _context.FmsMaterialRelease/*.AsNoTracking()*/;
            return query;
        }

        public FmsMaterialRelease Get(int id, int siteId) {
            var data = _context.FmsMaterialRelease.Single(x => x.MaterialReleaseId == id && x.SiteId == siteId);
            return data;
        }

        public IQueryable<FmsMaterialRelease> Gets(int id, int siteId) {
            var data = _context.FmsMaterialRelease.Where(x => x.MaterialReleaseId == id && x.SiteId == siteId);
            return data;
        }

        public void Delete(int id, int siteId) {
            using (var transaction = _context.Database.BeginTransaction()) {
                var releaseDetail = _context.FmsMaterialReleaseDetail.First(x => x.MaterialReleaseId == id && x.SiteId == siteId);
                _context.FmsMaterialReleaseDetail.Remove(releaseDetail);
                _context.SaveChanges();

                var data = _context.FmsMaterialRelease.First(x => x.MaterialReleaseId == id && x.SiteId == siteId);
                _context.FmsMaterialRelease.Remove(data);
                _context.SaveChanges();

                transaction.Commit();
            }
        }

        public void Approval(string userId, ICollection<FmsMaterialRelease> data) {
            using (var transaction = _context.Database.BeginTransaction()) {
                foreach (var item in data) {
                    if (item.IsConfirmed == true) continue;

                    var persist = _context.FmsMaterialRelease
                                .Where(x => x.MaterialReleaseId == item.MaterialReleaseId && x.SiteId == item.SiteId).FirstOrDefault();
                    if (persist == null) {
                        throw new ServiceException("정보를 찾을 수 없습니다.");
                    }

                    persist.IsConfirmed = true;
                    persist.ConfirmedUserId = userId;
                    persist.ConfirmedDate = DateTime.Now;
                    _context.FmsMaterialRelease.Update(persist);
                    _context.SaveChanges();
                }

                transaction.Commit();
            }
        }

        public void ApprovalEach(int siteId, int id, string userId) {
            var persist = _context.FmsMaterialRelease
                        .Where(x => x.MaterialReleaseId == id && x.SiteId == siteId).FirstOrDefault();
            if (persist == null) {
                throw new ServiceException("정보를 찾을 수 없습니다.");
            }

            using (var transaction = _context.Database.BeginTransaction()) {
                persist.IsConfirmed = true;
                persist.ConfirmedUserId = userId;
                persist.ConfirmedDate = DateTime.Now;
                _context.FmsMaterialRelease.Update(persist);
                _context.SaveChanges();

                transaction.Commit();
            }
        }
    }
}