using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using Microsoft.AspNetCore.Mvc;
using Siger.ApiCommon.Result;
using Siger.Middlelayer.AccRepository.Entities;
using Siger.Middlelayer.AccRepository.Repositories.Interface;
using Siger.Middlelayer.AccRepository.Response;
using Siger.Middlelayer.AccRepository.Request;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Repository.Repositories.Interface;
using Siger.Middlelayer.Repository;
using Siger.Middlelayer.Repository.Extensions;
using System.Linq;
using Siger.Middlelayer.Repository.Entities;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Utility.Helpers;
using System.IO;
using Siger.Middlelayer.Utility.ImportEntities;
using Siger.Middlelayer.Log;

namespace Siger.ApiACC.Controllers
{
    public class FixtureToolsAssemblyController : BaseController
    {
        private readonly IUnitOfWork _unitOfWork;
        private readonly IAutomationFixtureToolsCategoryRepository _toolsCategoryRepository;
        private readonly IAutomationFixtureToolsRepository _toolsRepository;
        private readonly IAutomationFixtureToolsAssemblyRepository _toolsAssemblyRepository;

        public FixtureToolsAssemblyController(IUnitOfWork unitOfWork, IAutomationFixtureToolsCategoryRepository toolsCategoryRepository, 
            IAutomationFixtureToolsRepository toolsRepository, IAutomationFixtureToolsAssemblyRepository toolsAssemblyRepository)
        {
            _unitOfWork = unitOfWork;
            _toolsCategoryRepository = toolsCategoryRepository;
            _toolsRepository = toolsRepository;
            _toolsAssemblyRepository = toolsAssemblyRepository;
        }

        /// <summary>
        ///TODO 子类查询可优化掉
        /// </summary>
        /// <param name="category"></param>
        /// <param name="code"></param>
        /// <param name="name"></param>
        /// <param name="state"></param>
        /// <param name="page"></param>
        /// <param name="pagesize"></param>
        /// <param name="toexcel"></param>
        /// <returns></returns>
        [HttpGet]
        public IActionResult GetPageList(string category, string code, string name, string state, int page, int pagesize, string toexcel = "")
        {
            var data = _toolsAssemblyRepository.GetPagedList(category.ToInt(), code, name, state, ProjectId, page, pagesize, toexcel);
            var categorys = _toolsCategoryRepository.GetList(q => q.projectId == ProjectId && q.status == (int)RowState.Valid).ToList();
            var list = new List<ResponseAumationFixtureToolsAssemblys>();
            foreach(var item in data.Data)
            {
                var cates = GetParentCategoryList(item.cate_guid, categorys);
                var cateIds = cates.Select(q => q.id).ToList();
                cateIds.Reverse();
                item.categoryids = cateIds;

                var parentcates = GetParentCategoryList(item.parentcate_guid, categorys);
                var parentcateIds = parentcates.Select(q => q.id).ToList();
                parentcateIds.Reverse();
                item.parentcategoryids = parentcateIds;

                var models = new List<ResponseAumationFixtureToolsAssembly>();
                var details = _toolsAssemblyRepository.GetDetailList(item.fixtureguid, category.ToInt(), code, name, state, ProjectId);
                if (!details.Any())
                {
                    details = _toolsAssemblyRepository.GetDetailList(item.fixtureguid, 0, "", "", "", ProjectId);//这里是为了符合测试的逻辑，当父级找到，子级找不到时，也把子级全部显示出来
                }
                foreach(var model in details)
                {
                    var cates1 = GetParentCategoryList(model.cate_guid, categorys);
                    var cateIds1 = cates1.Select(q => q.id).ToList();
                    cateIds1.Reverse();
                    model.categoryids = cateIds1;

                    var parentcates1 = GetParentCategoryList(model.parentcate_guid, categorys);
                    var parentcateIds1 = parentcates1.Select(q => q.id).ToList();
                    parentcateIds1.Reverse();
                    model.parentcategoryids = parentcateIds1;
                    model.fileurl = item.fileurl;
                    model.filename = item.filename;
                    model.remark = item.remark;
                    models.Add(model);
                }
                item.childrens = models;

                list.Add(item);
            }

            if(toexcel.ToInt() == 1)
            {
                return ExportExcel(list);
            }
            return new PagedObjectResult(list, data.Total, page, pagesize);
        }

        private IActionResult ExportExcel(IEnumerable<ResponseAumationFixtureToolsAssembly> data)
        {
            var rootDir = FileSystemHelper.GetPhysicalFolders(FileSystemHelper.CommonFileSetting.PhysicalFolder, FileSystemHelper.ExportFileName);

            if (!data.Any())
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            var dataList = new List<FixtureToolsAssmeblyList>();

            foreach (var item in data)
            {
                dataList.Add(new FixtureToolsAssmeblyList
                {
                    ParentCategory = item.category,
                    ParentPartNumber = item.partnumber,
                    ParentFixtureTool = item.name,
                    ParentSpecfication = item.specfication,
                    ParentCode = item.code,
                    Category = "",
                    FixtureTool = "",
                    PartNumber = "",
                    Specfication = "",
                    Status = item.status == (int)RowState.Valid ? "可用" : "停用",
                    Remark = item.remark,
                    Updator = item.updator,
                    UpdateTime = item.updatetime
                });
                if (item.childrens.Any())
                {
                    foreach(var son in item.childrens)
                    {
                        dataList.Add(new FixtureToolsAssmeblyList
                        {
                            ParentCategory = son.parentcategory,
                            ParentPartNumber = son.parentpartnumber,
                            ParentFixtureTool = son.parentname,
                            ParentSpecfication = son.parentspecfication,
                            ParentCode = son.parentcode,
                            Category = son.category,
                            FixtureTool = son.name,
                            PartNumber = son.partnumber,
                            Specfication = son.specfication,
                            Code = son.code,
                            Status = son.status == (int)RowState.Valid ? "可用" : "停用",
                            Remark = son.remark,
                            Updator = son.updator,
                            UpdateTime = son.updatetime
                        });
                    }
                }
            }
            if (dataList.Any())
            {
                EpPlusExcelHelper<FixtureToolsAssmeblyList> helper = null;
                try
                {
                    helper = new EpPlusExcelHelper<FixtureToolsAssmeblyList>();
                    var temporaryFileName = $"工装装配_FixtureToolsAssemblyData_{DateTime.Now:yyyyMMddHHmmss}.xlsx";
                    helper.GenerateExcel(dataList, Path.Combine(rootDir, temporaryFileName));
                    return new ObjectResult($"{FileSystemHelper.CommonFileSetting.RequestPath}/{FileSystemHelper.ExportFileName}/{temporaryFileName}");
                }
                catch (Exception e)
                {
                    Logger.WriteLineError("Export Fixture Tools Assembly Data failed, error:" + e);
                    throw new BadRequestException(RequestEnum.ExportFailed);
                }
                finally
                {
                    helper?.Dispose();
                }
            }

            throw new BadRequestException(CommonEnum.Fail);
        }

        private IEnumerable<siger_automation_fixture_tools_category> GetParentCategoryList(string parentId, List<siger_automation_fixture_tools_category> sections)
        {
            var query = from c in sections where c.guid == parentId select c;

            return query.ToList().Concat(query.ToList().SelectMany(t => GetParentCategoryList(t.parent, sections)));
        }

        [HttpGet]
        public IActionResult GetDetail(string guid)
        {
            var data = _toolsAssemblyRepository.GetDetailList(guid, 0 , "", "", "", ProjectId);

            return new ObjectResult(data);
        }

        [HttpPost]
        public IActionResult Add([FromBody]RequestAddFixtureToolAssembly req)
        {
            if (string.IsNullOrEmpty(req.fixturetoolid))
            {
                throw new BadRequestException(RequestEnum.ParameterMiss);
            }
            if(req.parentid == req.fixturetoolid)
            {
                throw new BadRequestException(RequestEnum.ParentSonSame);
            }
            var parent = _toolsRepository.Get(q => q.id == req.parentid.ToInt() && q.projectId == ProjectId);
            if (parent == null)
            {
                throw new BadRequestException(RequestEnum.FixtureToolNotFound);
            }
            var son = _toolsRepository.Get(q => q.id == req.fixturetoolid.ToInt() && q.projectId == ProjectId);
            if (son == null)
            {
                throw new BadRequestException(RequestEnum.FixtureToolNotFound);
            }
            var parentGuid = parent.guid;
            var exsit = _toolsAssemblyRepository.Get(q => q.projectId == ProjectId && q.son == son.guid && q.parent == parentGuid);
            if (exsit != null)
            {
                throw new BadRequestException(RequestEnum.DataExist);
            }
            var parentExsit = _toolsAssemblyRepository.Get(q => q.projectId == ProjectId && q.son == parentGuid);
            if(parentExsit != null && !string.IsNullOrEmpty(parentExsit.parent))
            {
                throw new BadRequestException(RequestEnum.LevelCountError);
            }

            if (parentExsit != null)
            {
                parentExsit.filename = req.filename;
                parentExsit.attachment = req.fileurl;
                parentExsit.remark = req.remark;
                parentExsit.updator = UserId;
                parentExsit.updatetime = DateTime.Now;

                //var sons = _toolsAssemblyRepository.GetList(q => q.parent == parentExsit.son && q.projectId == ProjectId).ToList();
                //if (req.status.ToInt() == (int)RowState.Invalid && sons.Count(q => q.status == (int)RowState.Invalid) == sons.Count)
                //{
                //    parentExsit.status = (int)RowState.Invalid;
                //}
                //else
                //{
                //    parentExsit.status = (int)RowState.Valid;
                //}

                _toolsAssemblyRepository.Update(parentExsit);
            }

            if (parentExsit == null)
            {
                var parentEntity = new siger_automation_fixture_tools_assembly
                {
                    guid = Guid.NewGuid().ToString(),
                    parent = "",
                    son = parent.guid,
                    creator = UserId,
                    createtime = DateTime.Now,
                    attachment = req.fileurl,
                    filename = req.filename,
                    projectId = ProjectId,
                    updatetime = DateTime.Now,
                    updator = UserId,
                    status = req.status.ToInt() == (int)RowState.Valid ? (int)RowState.Valid : (int)RowState.Invalid,
                    remark = req.remark
                };

                _toolsAssemblyRepository.Insert(parentEntity);
            }

            var entity = new siger_automation_fixture_tools_assembly
            {
                guid = Guid.NewGuid().ToString(),
                parent = parentGuid,
                son = son.guid,
                creator = UserId,
                createtime = DateTime.Now,
                attachment = req.fileurl,
                filename = req.filename,
                projectId = ProjectId,
                updatetime = DateTime.Now,
                updator = UserId,
                status = req.status.ToInt() == (int)RowState.Valid ? (int)RowState.Valid : (int)RowState.Invalid,
            };
            _toolsAssemblyRepository.Insert(entity);
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            else
            {
                throw new BadRequestException(CommonEnum.Fail);
            }
        }

        [HttpPost]
        public IActionResult Update([FromBody]RequestUpdateFixtureToolAssembly req)
        {
            if (string.IsNullOrEmpty(req.fixturetoolid))
            {
                throw new BadRequestException(RequestEnum.ParameterMiss);
            }
            if (!string.IsNullOrEmpty(req.parentid) && !string.IsNullOrEmpty(req.fixturetoolid) &&
                req.parentid == req.fixturetoolid)
            {
                throw new BadRequestException(RequestEnum.ParentSonSame);
            }
            var entity = _toolsAssemblyRepository.Get(q => q.projectId == ProjectId && q.id == req.id);
            if(entity == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            var parent = _toolsRepository.Get(q => q.id == req.parentid.ToInt() && q.projectId == ProjectId);
            if (parent == null)
            {
                throw new BadRequestException(RequestEnum.FixtureToolNotFound);
            }
            var son = _toolsRepository.Get(q => q.id == req.fixturetoolid.ToInt() && q.projectId == ProjectId);
            if (son == null)
            {
                throw new BadRequestException(RequestEnum.FixtureToolNotFound);
            }
            var parentGuid = parent.guid;
            var exsit = _toolsAssemblyRepository.Get(q => q.projectId == ProjectId && q.son == son.guid && q.parent == parentGuid &&
                q.id != req.id);
            if (exsit != null)
            {
                throw new BadRequestException(RequestEnum.DataExist);
            }
            var parentExsit = _toolsAssemblyRepository.Get(q => q.projectId == ProjectId && q.son == parentGuid);
            if (parentExsit != null && !string.IsNullOrEmpty(parentExsit.parent))
            {
                throw new BadRequestException(RequestEnum.LevelCountError);
            }

            if (parentExsit != null)
            {
                parentExsit.filename = req.filename;
                parentExsit.attachment = req.fileurl;
                parentExsit.remark = req.remark;
                parentExsit.updator = UserId;
                parentExsit.updatetime = DateTime.Now;

                //var sons = _toolsAssemblyRepository.GetList(q => q.parent == parentExsit.son && q.projectId == ProjectId).ToList();
                //if (req.status.ToInt() == (int)RowState.Invalid && sons.Count(q => q.status == (int)RowState.Invalid) == sons.Count)
                //{
                //    parentExsit.status = (int)RowState.Invalid;
                //}
                //else
                //{
                //    parentExsit.status = (int)RowState.Valid;
                //}

                _toolsAssemblyRepository.Update(parentExsit);
            }

            if (parentExsit == null)
            {
                var parentEntity = new siger_automation_fixture_tools_assembly
                {
                    guid = Guid.NewGuid().ToString(),
                    parent = "",
                    son = parent.guid,
                    creator = UserId,
                    createtime = DateTime.Now,
                    attachment = req.fileurl,
                    filename = req.filename,
                    projectId = ProjectId,
                    updatetime = DateTime.Now,
                    updator = UserId,
                    remark = req.remark,
                    status = req.status.ToInt() == (int)RowState.Valid ? (int)RowState.Valid : (int)RowState.Invalid,
                };
                _toolsAssemblyRepository.Insert(parentEntity);
            }

            entity.parent = parentGuid;
            entity.son = son.guid;
            entity.attachment = req.fileurl;
            entity.filename = req.filename;
            entity.updatetime = DateTime.Now;
            entity.updator = UserId;
            entity.status = req.status.ToInt() == (int)RowState.Valid ? (int)RowState.Valid : (int)RowState.Invalid;
            entity.remark = req.remark;
            _toolsAssemblyRepository.Update(entity);
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            else
            {
                throw new BadRequestException(CommonEnum.Fail);
            }
        }

        [HttpGet]
        public IActionResult Delete(int id)
        {
            var entity = _toolsAssemblyRepository.Get(q => q.projectId == ProjectId && q.id == id);
            if (entity == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            var sons = _toolsAssemblyRepository.GetList(q => q.projectId == ProjectId && q.parent == entity.son).ToList();
            foreach(var son in sons)
            {
                _toolsAssemblyRepository.Delete(son);
            }
            _toolsAssemblyRepository.Delete(entity);
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            else
            {
                throw new BadRequestException(CommonEnum.Fail);
            }
        }

        [HttpPost]
        public IActionResult Deletes([FromBody]RequestDeleteRange req)
        {
            if (req.ids == null || !req.ids.Any())
            {
                throw new BadRequestException(RequestEnum.ParameterMiss);
            }
            var entities = _toolsAssemblyRepository.GetList(t => req.ids.Contains(t.id) && t.projectId == ProjectId).ToList();
            if (!entities.Any())
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            var sons = _toolsAssemblyRepository.GetList(q => q.projectId == ProjectId && entities.Select(t => t.son).Contains(q.parent)).ToList();
            foreach (var son in sons)
            {
                _toolsAssemblyRepository.Delete(son);
            }
            foreach (var entity in entities)
            {
                _toolsAssemblyRepository.Delete(entity);
            }

            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            else
            {
                throw new BadRequestException(CommonEnum.Fail);
            }            
        }
    }
}
