using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.EntityFrameworkCore;
using Siger.Middlelayer.Common;
using Siger.Middlelayer.Common.Extensions;
using Siger.Middlelayer.Common.Helpers;
using Siger.Middlelayer.Common.ModuleEnum;
using Siger.Middlelayer.Utility.ExcelImport;
using Siger.Middlelayer.Utility.ImportEntities;
using Siger.Middlelayer.WmsRepository.Entities;
using Siger.Middlelayer.WmsRepository.Repositories.Interface;
using Siger.Middlelayer.WmsRepository.Request;

namespace Siger.Middlelayer.WmsRepository.Repositories
{
    internal class siger_wms_storage_locationRepository : WMSRepositoryBase<siger_wms_storage_location>, Isiger_wms_storage_locationRepository
    {
        private readonly ApiWmsDbContext dbContext;
        public siger_wms_storage_locationRepository(ApiWmsDbContext context) : base(context)
        {
            dbContext = context;
        }

        public string GenInventoryLevel(int material_id, int ProjectId)
        {
            var entity = dbContext.siger_tr_materials.FirstOrDefault(f =>f.id== material_id&& f.status == (int)RowState.Valid && f.projectId == ProjectId);
            if (entity == null)
            {
                throw new BadRequestException(CommonEnum.NoData);
            }
            var result = new StringBuilder();
            int typeid = entity.typeid;
            while (0 != typeid)
            {
                var type = dbContext.siger_tr_material_type.FirstOrDefault(f => f.id == typeid && f.status == (int)RowState.Valid && f.projectId == ProjectId);
                if (type == null)
                {
                    throw new BadRequestException(RequestEnum.ErrorMaterialType);
                }
                result.Insert(0, type.tcode);
                typeid = type.parentid;
            }
            //添加最高的TOP层级
            result.Insert(0, CommonConst.MATERIALTYPE_PARENTNAME);

            return result.ToString();
        }

        public string GenNo(int locationid)
        {
            var ids = new List<int>();
            var entity = Get(locationid);
            if (entity == null)
                throw new BadRequestException(CommonEnum.NoData);
            var pid = entity.parentid;
            ids.Add(locationid);
            int i = 1;
            while (pid != 0)
            {
                var tmp = Get(pid);
                if (tmp == null)
                    throw new BadRequestException(CommonEnum.NoData);
                ids.Insert(0, tmp.id);
                pid = tmp.parentid;
                i++;
                if (i >= 4)
                    break;
            }
            var str = "";
            foreach (var item in ids)
            {
                str += item.ToString();
            }
            //str+=new Random().Next(999999).ToString("D6");
            return str;
        }

        private bool InsertData(ImportStorageLocations locationEntity, int projectid, int userid, List<siger_wms_storage_location_type> sonLocationTypes)
        {
            var locationTypeId = sonLocationTypes.LastOrDefault()?.id ?? 0;

            var ids = new List<int>();
            var parentid = 0;
            foreach (var locationType in sonLocationTypes)
            {
                var Location = locationEntity.Locations.FirstOrDefault(q => q.LocationType == locationType.id);
                if (Location == null)
                {
                    return false;
                }
                var tmp = new siger_wms_storage_location
                {
                    storageid = locationEntity.StorageId,
                    parentid = parentid,
                    name = "",
                    realname = Location.Location,
                    typeid = Location.LocationType,
                    serial_number = GenSerialNumber(),
                    creator = userid,
                    create_time = DateTime.Now,
                    updator = userid,
                    update_time = DateTime.Now,
                    projectid = projectid,
                    status = (int)RowState.Valid,
                    locationid = Location.LocationType == locationTypeId ? locationEntity.ID.ToInt() : 0
                };
                parentid = InsertLocation(tmp, locationEntity.StorageName, projectid);
                if (parentid > 0)
                {
                    ids.Add(parentid);
                    continue;
                }
                else
                {
                    foreach (var id in ids)
                    {
                        var entity = dbContext.siger_wms_storage_location.FirstOrDefault(q => q.id == id);
                        dbContext.siger_wms_storage_location.Remove(entity);
                    }
                    return false;
                }
            }
            return true;
        }
        private int InsertLocation(siger_wms_storage_location tmp, string waveHouseName, int projectid)
        {
            int id = 0;
            dbContext.siger_wms_storage_location.Add(tmp);
            if (dbContext.SaveChanges() <= 0)
            {
                return id;
            }

            //更新编号、层级名称
            var sn = new StringBuilder();
            sn.Append(tmp.id);
            var parent = dbContext.siger_wms_storage_location.FirstOrDefault(f => f.id == tmp.parentid && tmp.parentid != 0 && f.projectid == projectid && f.status == (int)RowState.Valid);
            var parentname = "";
            if (parent != null)
            {
                parentname = parent.name;
            }
            while (parent != null)
            {
                sn.Insert(0, parent.id + "_");
                parent = dbContext.siger_wms_storage_location.FirstOrDefault(f => f.id == parent.parentid && parent.parentid != 0 && f.projectid == projectid && f.status == (int)RowState.Valid);
            }
            //仓库
            sn.Insert(0, tmp.storageid + "_");
            tmp.serial_number = sn.ToString();

            //上级为仓库
            if (tmp.parentid == 0)
            {
                tmp.name = $"{waveHouseName} -> {tmp.realname}";
            }
            else
            {
                tmp.name = $"{parentname} -> {tmp.realname}";
            }
            dbContext.siger_wms_storage_location.Update(tmp);
            if (dbContext.SaveChanges() <= 0)
            {
                return id;
            }

            return tmp.id;
        }
        private IEnumerable<siger_wms_storage_location_type> GetSonTypes(int id, List<siger_wms_storage_location_type> types)
        {
            var query = from c in types where c.parentid == id select c;

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


        public CommonImportResult ImportStorageLocations(IEnumerable<ImportStorageLocations> locations, int projectid, int userid)
        {
            var locationTypes = dbContext.siger_wms_storage_location_type.Where(q => q.projectid == projectid && q.status == (int)RowState.Valid).ToList();
            if (!locationTypes.Any())
            {
                throw new BadRequestException(RequestEnum.LocationTypeNotFound);
            }
            var sonLocationTypes = GetSonTypes(0, locationTypes).ToList();
            var lastLocationTypeId = sonLocationTypes.LastOrDefault()?.id ?? 0;

            int rowIndex = 2;
            var errors = new List<string>();

            var list = new List<ImportStorageLocations>();
            foreach (var loca in locations)
            {
                if(!int.TryParse(loca.ID, out int id))
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.PleaseInputNotZeroIntID}");
                }

                if (string.IsNullOrEmpty(loca.StorageName))
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.PleaseInputStorageName}");
                }

                if (loca.Locations.Count != sonLocationTypes.Count)
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.LocationLevelError}");
                    return new CommonImportResult(0, string.Join(";", errors));
                }

                var storage = dbContext.siger_wms_storage.FirstOrDefault(q => q.name == loca.StorageName && q.projectid == projectid && q.status == (int)RowState.Valid);
                if (storage == null)
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.StorageError}");
                }
                else
                {
                    loca.StorageId = storage.id;
                }

                foreach (var typeId in loca.Locations)
                {
                    if(typeId.LocationType == 0)
                    {
                        errors.Add($"{rowIndex},{(int)RequestEnum.LocationLevelError}");
                    }
                    if (string.IsNullOrEmpty(typeId.Location))
                    {
                        errors.Add($"{rowIndex},{(int)RequestEnum.PleaseInputLocation}");
                    }
                    if(storage != null && typeId.LocationType > 0 && loca.ID.ToInt() > 0)
                    {
                        var locationIdExist = dbContext.siger_wms_storage_location.FirstOrDefault(q => q.projectid == projectid && 
                            q.status == (int)RowState.Valid && q.typeid == lastLocationTypeId && q.locationid == loca.ID.ToInt() && 
                            q.storageid == storage.id);
                        if (locationIdExist != null || locations.Count(q => q.StorageName == loca.StorageName && q.ID == loca.ID) > 1)
                        {
                            errors.Add($"{rowIndex},{(int)RequestEnum.IDExist}");
                            break;
                        }
                    }
                }

                if (errors.Any())
                {
                    return new CommonImportResult(0, string.Join(";", errors));
                }

                list.Add(loca);

                rowIndex++;
            }

            rowIndex = 2;
            foreach (var loca in list)
            {
                try
                {
                    if(!InsertData(loca, projectid, userid, locationTypes))
                    {
                        errors.Add($"{rowIndex},{(int)RequestEnum.ImportFailed}");
                        return new CommonImportResult(0, string.Join(";", errors));
                    }
                }                
                catch(Exception)
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.ImportFailed}");
                    return new CommonImportResult(0, string.Join(";", errors));
                }
                rowIndex++;
            }
            return new CommonImportResult(1, "1");
        }

        public CommonImportResult ImportStorageLocation(IEnumerable<ImportStorageLocation> locations, int projectid,int userid)
        {
            var errors = new List<string>();
            var rowIndex = 1;
            var types = dbContext.siger_wms_storage_location_type.Where(f => f.projectid == projectid && f.status != 0).OrderBy(o => o.id).AsNoTracking().ToList();
            var insertEntity = new List<siger_wms_storage_location>();

            foreach (var location in locations)
            {
                rowIndex++;
                //check levels
                var storageData = dbContext.siger_wms_storage.FirstOrDefault(f => f.projectid == projectid && f.status != 0 && f.name == location.StorageName);
                if (storageData==null)
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.StorageError}");
                    break;
                }
                var typeData = types.FirstOrDefault(f => f.name == location.LocationType);
                if (typeData == null)
                {
                    errors.Add($"{rowIndex},{(int)RequestEnum.LocationError}");
                    break;
                }
                var name = location.LocationName;
                var parentid = 0;
                if (!string.IsNullOrEmpty(location.ParentLocation))
                {
                    var parentData = dbContext.siger_wms_storage_location.FirstOrDefault(f => f.storageid == storageData.id && f.projectid == projectid && f.status != 0 && f.realname == location.ParentLocation);
                    if (parentData == null)
                    {
                        errors.Add($"{rowIndex},{(int)RequestEnum.LocationPidNotExist}");
                        break;
                    }
                    if (parentData.typeid >= typeData.id)
                    {
                        errors.Add($"{rowIndex},{(int)RequestEnum.LocationPidCanNotBySelf}");
                        break;
                    }
                    name = parentData.name + "->" + location.LocationName;
                    parentid = parentData.id;
                }
                var model = dbContext.siger_wms_storage_location.FirstOrDefault(f => f.storageid == storageData.id && f.projectid == projectid && f.status != 0 && f.realname == location.LocationName);
                if (model!=null)
                {
                    errors.Add($"{rowIndex},{(int)CommonEnum.RecordExits}");
                    break;
                }
                if (insertEntity.Any(f => f.storageid == storageData.id && f.realname == location.LocationName))
                {
                    errors.Add($"{rowIndex},{(int)CommonEnum.RecordExits}");
                    break;
                }
                insertEntity.Add(new siger_wms_storage_location
                {
                    create_time = DateTime.Now,
                    creator = userid,
                    level = 0,
                    realname = location.LocationName,
                    name = name,
                    option = "",
                    parentid = parentid,
                    projectid = projectid,
                    storageid = storageData.id,
                    updator = userid,
                    update_time = DateTime.Now,
                    typeid = typeData.id,
                    serial_number = GenSerialNumber(),
                    status=1,
                });
            }
            if (errors.Any())
            {
                return new CommonImportResult(0, string.Join(";", errors));
            }
            dbContext.siger_wms_storage_location.AddRange(insertEntity);
            dbContext.SaveChanges();
            return new CommonImportResult(1, "1");
        }

        public string GenSerialNumber()
        {
            return $"{GenKey()}{UnixTimeHelper.GetNow()}";
        }
        private string GenKey()
        {
            char value1 = (char)((new Random().Next() % 26) + 'A');
            char value2 = (char)((new Random().Next() % 26) + 'A');
            return $"{value1}{value2}";
        }
    }
}

