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

namespace Siger.ApiACC.Controllers
{
    public class AutomationLocationController : BaseController
    {
        private readonly IUnitOfWork _unitOfWork;
        private readonly IAutomationFixtureToolsCategoryRepository _toolsCategoryRepository;
        private readonly IAutomationFixtureToolsRepository _toolsRepository;
        private readonly IAutomationLocationRepository _autoLocationRepository;
        private readonly IAutomationFixtureMonitor _fixtureMonitor;
        private readonly IProductRouteRepository _routeRepository;
        private readonly IAutomationFixtureToolsProductRepository _automationFixtureToolsProduct;

        public AutomationLocationController(IUnitOfWork unitOfWork, IAutomationFixtureToolsCategoryRepository toolsCategoryRepository, 
            IAutomationFixtureToolsRepository toolsRepository, IAutomationLocationRepository autoLocationRepository,
            IAutomationFixtureMonitor fixtureMonitor, IProductRouteRepository routeRepository,IAutomationFixtureToolsProductRepository automationFixtureToolsProduct)
        {
            _unitOfWork = unitOfWork;
            _toolsCategoryRepository = toolsCategoryRepository;
            _toolsRepository = toolsRepository;
            _autoLocationRepository = autoLocationRepository;
            _fixtureMonitor = fixtureMonitor;
            _routeRepository = routeRepository;
            _automationFixtureToolsProduct = automationFixtureToolsProduct;
        }

        [HttpGet]
        public IActionResult GetPageList(string wavehouseid, string locationid, int page, int pagesize, string toexcel)
        {
            var locations = _autoLocationRepository.GetLocationList(ProjectId);
            var locationids = new List<int>();
            if(locationid.ToInt() > 0)
            {
                var searchLocations = GetSonLocations(locationid.ToInt(), locations);
                locationids = searchLocations.Select(q => q.id).ToList();
                locationids.Add(locationid.ToInt());
            }
            var data = _autoLocationRepository.GetPagedList(wavehouseid.ToInt(), locationids, ProjectId, page, pagesize, toexcel);
            var list = new List<ResponseAutomationLocation>();            
            var categorys = _toolsCategoryRepository.GetList(q => q.projectId == ProjectId && q.status == (int)RowState.Valid).ToList();
            foreach (var item in data.Data)
            {
                if(item.fixturetoolid > 0 && string.IsNullOrEmpty(item.sn))
                {
                    item.materialstate = 1;//有工装无工件
                }
                else if(item.fixturetoolid > 0 && !string.IsNullOrEmpty(item.sn))
                {
                    item.materialstate = 2;//有工装有工件
                }
                else if (item.fixturetoolid <= 0 && string.IsNullOrEmpty(item.sn))
                {
                    item.materialstate = 3;//无工装无工件
                }
                else if (item.fixturetoolid <= 0 && string.IsNullOrEmpty(item.sn))
                {
                    item.materialstate = 4;//无工装有工件
                }

                var loca = locations.FirstOrDefault(q => q.id == item.locationid);
                if(loca != null)
                {
                    var locas = GetParentLocations(loca.id, locations);
                    var locationIds = locas.Select(q => q.id).ToList();
                    locationIds = locationIds.Distinct().ToList();
                    locationIds.Reverse();
                    item.locationIds = locationIds;
                }

                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);
            }
            else
            {
                return new PagedObjectResult(list, data.Total, page, pagesize);
            }            
        }

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

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

            foreach (var item in data)
            {
                var state = "";
                switch (item.materialstate)
                {
                    case 1:
                        state = "有工装无工件";
                        break;
                    case 2:
                        state = "有工装有工件";
                        break;
                    case 3:
                        state = "无工装无工件";
                        break;
                    case 4:
                        state = "无工装有工件";
                        break;
                }
                dataList.Add(new AutomationLocationList
                {
                    Warehouse = item.wavehouse,
                    Location = item.location,
                    LocationId = item.locaid.ToString(),
                    Catgeory = item.category,
                    Code = item.code,
                    Name = item.fixturetool,
                    Specfication = item.specfication,
                    SN = item.sn,
                    RouteNumber = item.routenumber,
                    RouteName = item.route,
                    State = state,
                    Remark = item.remark,
                    Updator = item.updator,
                    UpdateTime = item.updatetime
                });
            }
            if (dataList.Any())
            {
                EpPlusExcelHelper<AutomationLocationList> helper = null;
                try
                {
                    helper = new EpPlusExcelHelper<AutomationLocationList>();
                    var temporaryFileName = $"储位信息查询_FixtureToolsLocationData_{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 Location 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)));
        }

        private IEnumerable<siger_wms_storage_location> GetParentLocations(int pid, IEnumerable<siger_wms_storage_location> types)
        {
            var query = from c in types where c.id == pid select c;

            return query.ToList().Concat(query.ToList().SelectMany(t => GetParentLocations(t.parentid, types)));
        }

        private IEnumerable<siger_wms_storage_location> GetSonLocations(int id, IEnumerable<siger_wms_storage_location> types)
        {
            var query = from c in types where c.parentid == id select c;

            return query.ToList().Concat(query.ToList().SelectMany(t => GetSonLocations(t.id, types)));
        }

        [HttpPost]
        public IActionResult Add([FromBody]RequestAddAutomationLocation req)
        {
            if (string.IsNullOrEmpty(req.locationid) || string.IsNullOrEmpty(req.fixturetoolid))
            {
                throw new BadRequestException(RequestEnum.ParameterMiss);
            }
            var fixturetool = _toolsRepository.Get(q => q.id == req.fixturetoolid.ToInt() && q.projectId == ProjectId);
            if (fixturetool == null)
            {
                throw new BadRequestException(RequestEnum.FixtureToolNotFound);
            }
            var fixturetoolProduct = _automationFixtureToolsProduct.Get(f => f.fixturetools == fixturetool.guid);
      
            var location = _autoLocationRepository.GetLocation(req.locationid.ToInt(), ProjectId);
            if (location == null)
            {
                throw new BadRequestException(RequestEnum.LocationNull);
            }
            var exsit = _autoLocationRepository.Get(q => q.projectId == ProjectId && q.status == (int)RowState.Valid &&
                (q.fixturetools == fixturetool.guid || q.location_cid == req.locationid.ToInt()));
            if(exsit != null)
            {
                throw new BadRequestException(RequestEnum.DataExist);
            }

            var entity = new siger_automation_location
            {
                guid = Guid.NewGuid().ToString(),
                locationid = location.locationid,
                location_cid = location.id,
                fixturetools = fixturetool.guid,
                productid= fixturetoolProduct != null ? fixturetoolProduct.productid : 0,
                productcode = fixturetoolProduct!=null? fixturetoolProduct.productcode:"",
                attachment = req.fileurl,
                filename = req.filename,
                remark = req.remark,
                projectId = ProjectId,
                updatetime = DateTime.Now,
                updator = UserId,
            };
            _autoLocationRepository.Insert(entity);
            if (_unitOfWork.Commit() > 0)
            {
                return new ObjectResult(CommonEnum.Succefull);
            }
            else
            {
                throw new BadRequestException(CommonEnum.Fail);
            }
        }

        [HttpPost]
        public IActionResult Update([FromBody]RequestUpdateAutomationLocation req)
        {
            if (string.IsNullOrEmpty(req.locationid) || string.IsNullOrEmpty(req.fixturetoolid))
            {
                throw new BadRequestException(RequestEnum.ParameterMiss);
            }
            var entity = _autoLocationRepository.Get(q => q.id == req.id && q.projectId == ProjectId && q.status == (int)RowState.Valid);
            if(entity == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            var fixturetool = _toolsRepository.Get(q => q.id == req.fixturetoolid.ToInt() && q.projectId == ProjectId);
            if (fixturetool == null)
            {
                throw new BadRequestException(RequestEnum.FixtureToolNotFound);
            }
            var fixturetoolProduct = _automationFixtureToolsProduct.Get(f => f.fixturetools == fixturetool.guid);
            var location = _autoLocationRepository.GetLocation(req.locationid.ToInt(), ProjectId);
            if (location == null)
            {
                throw new BadRequestException(RequestEnum.LocationNull);
            }
            var exsit = _autoLocationRepository.Get(q => q.projectId == ProjectId && q.status == (int)RowState.Valid &&
                (q.fixturetools == fixturetool.guid || q.location_cid == req.locationid.ToInt()) && q.id != req.id);
            if (exsit != null)
            {
                throw new BadRequestException(RequestEnum.DataExist);
            }

            entity.locationid = location.locationid;
            entity.location_cid = location.id;
            entity.fixturetools = fixturetool.guid;
            entity.attachment = req.fileurl;
            entity.filename = req.filename;
            entity.remark = req.remark;
            entity.updatetime = DateTime.Now;
            entity.updator = UserId;
            entity.productid = fixturetoolProduct != null ? fixturetoolProduct.productid : 0;
            entity.productcode = fixturetoolProduct != null ? fixturetoolProduct.productcode : "";

            _autoLocationRepository.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 = _autoLocationRepository.Get(q => q.projectId == ProjectId && q.status == (int)RowState.Valid && q.id == id);
            if (entity == null)
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }

            entity.status = (int)RowState.Invalid;
            _autoLocationRepository.Update(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 = _autoLocationRepository.GetList(t =>
                req.ids.Contains(t.id) && t.projectId == ProjectId && t.status == (int)RowState.Valid).ToList();
            if (!entities.Any())
            {
                throw new BadRequestException(CommonEnum.RecordNotFound);
            }
            foreach (var entity in entities)
            {
                entity.status = (int)RowState.Invalid;
                _autoLocationRepository.Update(entity);
            }

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

        [HttpGet]
        public IActionResult GetLocationList()
        {
            return new ObjectResult(_autoLocationRepository.GetDataList(ProjectId).ToList());
        }
    }
}
