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 Siger.Middlelayer.Utility.ImportEntities;
using System.IO;
using Siger.Middlelayer.Log;

namespace Siger.ApiACC.Controllers
{
    public class FixtureToolsController : BaseController
    {
        private readonly IUnitOfWork _unitOfWork;
        private readonly IAutomationFixtureToolsCategoryRepository _toolsCategoryRepository;
        private readonly IAutomationFixtureToolsRepository _toolsRepository;
        private readonly IAutomationLocationRepository _automationLocationRepository;

        public FixtureToolsController(IUnitOfWork unitOfWork, IAutomationFixtureToolsCategoryRepository toolsCategoryRepository, 
            IAutomationFixtureToolsRepository toolsRepository, IAutomationLocationRepository automationLocationRepository)
        {
            _unitOfWork = unitOfWork;
            _toolsCategoryRepository = toolsCategoryRepository;
            _toolsRepository = toolsRepository;
            _automationLocationRepository = automationLocationRepository;
        }

        public IActionResult GetPageList(string category, string code, string name, string state, int page, int pagesize, string toexcel)
        {
            var categorys = _toolsCategoryRepository.GetList(q => q.projectId == ProjectId && q.status == (int)RowState.Valid).ToList();
            var categoryIds = new List<int>();
            if(category.ToInt() > 0)
            {
                var cate = categorys.FirstOrDefault(q => q.id == category.ToInt());
                var sonCates = GetSonCategoryList(cate.guid, categorys);
                categoryIds = sonCates.Select(q => q.id).ToList();
                categoryIds.Add(category.ToInt());
            }
            var data = _toolsRepository.GetPagedList(categoryIds, code, name, string.IsNullOrEmpty(state) ? -1 : state.ToInt(), ProjectId, page, pagesize, toexcel);
            var list = new List<ResponseFixtureTools>();            
            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;
                list.Add(item);
            }
            if (toexcel.ToInt() == 1)
            {
                return ExportExcel(list);
            }
            return new PagedObjectResult(list, data.Total, page, pagesize);
        }

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

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

            foreach (var item in data)
            {
                dataList.Add(new FixtureToolsList
                {
                    Catgeory = item.category,
                    Name = item.name,
                    Manage = item.managetype == 1 ? "单件" : "批次",
                    PartNumber = item.partnumber,
                    Code = item.code,
                    Specfication = item.specification,
                    Number = item.number.ToString(),
                    Status = item.status == 1 ? "可用" : "停用",
                    Remark = item.remark,
                    Updator = item.updator,
                    UpdateTime = item.updatetime
                });
            }
            if (dataList.Any())
            {
                EpPlusExcelHelper<FixtureToolsList> helper = null;
                try
                {
                    helper = new EpPlusExcelHelper<FixtureToolsList>();
                    var temporaryFileName = $"工装台账_FixtureToolsData_{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 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)));
        }

        [HttpPost]
        public IActionResult Add([FromBody]RequestAddFixtureTools req)
        {
            if(string.IsNullOrEmpty(req.partnumber) || string.IsNullOrEmpty(req.code) || string.IsNullOrEmpty(req.name) || string.IsNullOrEmpty(req.categoryid) ||
                    string.IsNullOrEmpty(req.managetype))
            {
                throw new BadRequestException(RequestEnum.ParameterMiss);
            }
            var data = _toolsRepository.Get(q => q.projectId == ProjectId && q.code == req.code);
            if (data != null)
            {
                throw new BadRequestException(RequestEnum.DataExist);
            }

            var category = _toolsCategoryRepository.Get(q => q.id == req.categoryid.ToInt() && q.projectId == ProjectId && q.status == (int)RowState.Valid);
            if(category == null)
            {
                throw new BadRequestException(RequestEnum.FixtureToolCatgeoryNotFound);
            }

            var entity = new siger_automation_fixture_tools
            {
                guid = Guid.NewGuid().ToString(),
                category = category.guid,
                managetype = req.managetype.ToInt(),
                partnumber = req.partnumber,
                name = req.name,
                specification = req.specifition,
                number = req.number.ToInt(),
                remark = req.remark,
                attachment = req.fileurl,
                filename = req.filename,
                code = req.code,
                projectId = ProjectId,
                status = req.status.ToInt() == (int)RowState.Valid ? (int)RowState.Valid : (int)RowState.Invalid,
                createtime = DateTime.Now,
                updatetime = DateTime.Now,
                creator = UserId,
                updator = UserId,
            };
            _toolsRepository.Insert(entity);
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            else
            {
                throw new BadRequestException(CommonEnum.Fail);
            }
        }

        [HttpPost]
        public IActionResult Update([FromBody]RequestUpdateFixtureTools req)
        {
            if (string.IsNullOrEmpty(req.partnumber) || string.IsNullOrEmpty(req.code) || string.IsNullOrEmpty(req.name) || string.IsNullOrEmpty(req.categoryid) ||
                    string.IsNullOrEmpty(req.managetype) || req.id <= 0)
            {
                throw new BadRequestException(RequestEnum.ParameterMiss);
            }
            var entity = _toolsRepository.Get(q => q.projectId == ProjectId && q.id == req.id);
            var data = _toolsRepository.Get(q => q.projectId == ProjectId && q.code == req.code && q.id != req.id);
            if (data != null)
            {
                throw new BadRequestException(RequestEnum.DataExist);
            }

            var category = _toolsCategoryRepository.Get(q => q.id == req.categoryid.ToInt() && q.projectId == ProjectId && q.status == (int)RowState.Valid);
            if (category == null)
            {
                throw new BadRequestException(RequestEnum.FixtureToolCatgeoryNotFound);
            }

            entity.category = category.guid;
            entity.managetype = req.managetype.ToInt();
            entity.partnumber = req.partnumber;
            entity.name = req.name;
            entity.specification = req.specifition;
            entity.number = req.number.ToInt();
            entity.remark = req.remark;
            entity.attachment = req.fileurl;
            entity.filename = req.filename;
            entity.code = req.code;
            entity.updatetime = DateTime.Now;
            entity.updator = UserId;
            entity.status = req.status.ToInt() == (int)RowState.Valid ? (int)RowState.Valid : (int)RowState.Invalid;
            _toolsRepository.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 = _toolsRepository.Get(q => q.projectId == ProjectId && q.id == id);
            if (entity == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            _toolsRepository.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 = _toolsRepository.GetList(t => req.ids.Contains(t.id) && t.projectId == ProjectId).ToList();
            if (!entities.Any())
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            foreach (var entity in entities)
            {
                _toolsRepository.Delete(entity);
            }

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



        [HttpGet]
        public IActionResult GetCategoryPageList(string id, int page, int pagesize, string toexcel = "")
        {
            var categorys = _toolsCategoryRepository.GetList(q => q.projectId == ProjectId && q.status == (int)RowState.Valid).ToList();
            var categoryIds = new List<int>();
            if (id.ToInt() > 0)
            {
                var cate = categorys.FirstOrDefault(q => q.id == id.ToInt());
                var sonCates = GetSonCategoryList(cate.guid, categorys);
                categoryIds = sonCates.Select(q => q.id).ToList();
                categoryIds.Add(id.ToInt());
            }
            var data = _toolsCategoryRepository.GetPagedList(categoryIds, ProjectId, page, pagesize, toexcel);
            if(toexcel.ToInt() == 1)
            {
                return ExportCategoryExcel(data.Data);
            }
            return new PagedObjectResult(data.Data, data.Total, page, pagesize);
        }

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

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

            foreach (var item in data)
            {
                dataList.Add(new FixtureToolsCategoryTemplate
                {
                    Fixture = item.name,
                    Parent = item.parentname
                });
            }
            if (dataList.Any())
            {
                EpPlusExcelHelper<FixtureToolsCategoryTemplate> helper = null;
                try
                {
                    helper = new EpPlusExcelHelper<FixtureToolsCategoryTemplate>();
                    var temporaryFileName = $"工装类型_FixtureToolsCategoryData_{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 Category Data failed, error:" + e);
                    throw new BadRequestException(RequestEnum.ExportFailed);
                }
                finally
                {
                    helper?.Dispose();
                }
            }

            throw new BadRequestException(CommonEnum.Fail);
        }

        [HttpPost]
        public IActionResult AddCategory([FromBody]RequestAddFixtureToolsCategory req)
        {
            var data = _toolsCategoryRepository.Get(q => q.projectId == ProjectId && q.status == (int)RowState.Valid && q.name == req.name);
            if (data != null)
            {
                throw new BadRequestException(RequestEnum.DataExist);
            }
            var parent = "";
            if(req.parentid.ToInt() > 0)
            {
                var exsit = _toolsCategoryRepository.Get(q => q.projectId == ProjectId && q.status == (int)RowState.Valid && q.id == req.parentid.ToInt());
                if(exsit == null)
                {
                    throw new BadRequestException(RequestEnum.ParentTypeError);
                }
                else
                {
                    parent = exsit.guid;
                }
            }

            var entity = new siger_automation_fixture_tools_category
            {
                name = req.name,
                parent = parent,
                guid = Guid.NewGuid().ToString(),
                projectId = ProjectId,
                createtime = DateTime.Now,
                updatetime = DateTime.Now,
            };
            _toolsCategoryRepository.Insert(entity);
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            else
            {
                throw new BadRequestException(CommonEnum.Fail);
            }
        }

        [HttpPost]
        public IActionResult UpdateCategory([FromBody]RequestUpdateFixtureToolsCategory req)
        {
            var entity = _toolsCategoryRepository.Get(q => q.projectId == ProjectId && q.status == (int)RowState.Valid && q.id == req.id);
            if(entity == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            var data = _toolsCategoryRepository.Get(q => q.projectId == ProjectId && q.status == (int)RowState.Valid && q.name == req.name && 
                q.id != req.id);
            if (data != null)
            {
                throw new BadRequestException(RequestEnum.DataExist);
            }
            var parent = "";
            if (req.parentid.ToInt() > 0)
            {
                var exsit = _toolsCategoryRepository.Get(q => q.projectId == ProjectId && q.status == (int)RowState.Valid && q.id == req.parentid.ToInt());
                if (exsit == null)
                {
                    throw new BadRequestException(RequestEnum.ParentTypeError);
                }
                else
                {
                    parent = exsit.guid;
                }
            }

            entity.name = req.name;
            entity.parent = parent;
            entity.updatetime = DateTime.Now;
            _toolsCategoryRepository.Update(entity);
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            else
            {
                throw new BadRequestException(CommonEnum.Fail);
            }
        }

        [HttpGet]
        public IActionResult DeleteCategory(int id)
        {
            var categorys = _toolsCategoryRepository.GetList(q => q.projectId == ProjectId && q.status == (int)RowState.Valid).ToList();
            var entity = categorys.FirstOrDefault(q => q.id == id);
            if (entity == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            var details = GetSonCategoryList(entity.guid, categorys).ToList();
            details.Add(entity);
            var detailGuids = details.Select(q => q.guid).Distinct().ToList();

            if (_toolsRepository.GetList(q => q.projectId == ProjectId && detailGuids.Contains(q.category)).Any())
            {
                throw new BadRequestException(RequestEnum.CategoryBindFixtureToolData);
            }

            var delDetails = _toolsCategoryRepository.GetList(q => q.projectId == ProjectId && q.status == (int)RowState.Valid &&
                detailGuids.Contains(q.guid)).ToList();

            foreach (var detail in delDetails)
            {
                detail.status = (int)RowState.Invalid;
                _toolsCategoryRepository.Update(detail);
            }
            if(_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            else
            {
                throw new BadRequestException(CommonEnum.Fail);
            }
        }

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

            return query.ToList().Concat(query.ToList().SelectMany(t => GetSonCategoryList(t.guid, sections)));
        }

        [HttpGet]
        public IActionResult GetCategoryList()
        {
            var list = _toolsCategoryRepository.GetList(q => q.projectId == ProjectId && q.status == (int)RowState.Valid).ToList();
            var res = GetChildren("", list);
            return new ObjectResult(res);
        }

        private List<FixtureToolsCategoryTree> GetChildren(string parentid, List<siger_automation_fixture_tools_category> sectionDatas)
        {
            var resp = new List<FixtureToolsCategoryTree>();
            var query = sectionDatas.Where(f => f.parent == parentid);
            if (!query.Any())
            {
                return null;
            }
            foreach (var section in query)
            {
                var data = new FixtureToolsCategoryTree
                {
                    value = section.id,
                    label = section.name
                };
                data.children = GetChildren(section.guid, sectionDatas);
                resp.Add(data);
            }
            return resp;
        }


        [HttpGet]
        public IActionResult GetFixtureToolList(string categoryid)
        {
            var categorys = _toolsCategoryRepository.GetList(q => q.projectId == ProjectId && q.status == (int)RowState.Valid).ToList();
            var categoryIds = new List<int>();
            if (categoryid.ToInt() > 0)
            {
                var cate = categorys.FirstOrDefault(q => q.id == categoryid.ToInt());
                var sonCates = GetSonCategoryList(cate.guid, categorys);
                categoryIds = sonCates.Select(q => q.id).ToList();
                categoryIds.Add(categoryid.ToInt());
            }
            var list = _toolsRepository.GetDataList(categoryIds, ProjectId);
            return new ObjectResult(list);
        }
    }
}
