using CloudBuilder.Core.DatabaseAccessor;
using CloudBuilder.Core.DatabaseAccessor.Entity;
using CloudBuilder.Core.Extensions;
using CloudBuilder.Core.Report;
using CloudBuilder.Core.Service;
using CloudBuilder.Security.Data;
using CloudBuilder.Security.Entity;
using CloudBuilder.Security.Policy;
using CloudBuilder.Security.SearchCriteria;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace CloudBuilder.Security.Service
{
    public class SecurityGeneratorNumberService : ISecurityGeneratorNumberService
    {
        private readonly IApplicationService service;

        private IRepository<SecurityGeneratorNumberEntity> repository;
        public SecurityGeneratorNumberService(IApplicationService service)
        {
            this.service = service;
            repository = service.GetRepository<IRepository<SecurityGeneratorNumberEntity>>();
        }

        [PermissionOperate(name: SecurityPermissionPolicy.SecurityGeneratorNumber, operate: Operate.Find)]
        public SecurityGeneratorNumberEntity FindByKey(int key)
        {
            return repository.DetachedEntities.Where(x => x.GeneratorId == key).FirstOrDefault()!;
        }

        [PermissionOperate(name: SecurityPermissionPolicy.SecurityGeneratorNumber, operate: Operate.Find)]
        public SecurityGeneratorNumberResultData FindBySearchCriteria(SecurityGeneratorNumberSearchCriteria criteria)
        {
            SecurityGeneratorNumberResultData data = new SecurityGeneratorNumberResultData();
            SecurityGeneratorNumberEntity[] list = null;

            int count = 0;

            string sqlWhere = null;

            if (criteria.Filter != null && criteria.Filter.Length > 0)
            {
                sqlWhere = SearchFilter.ComposeWhereClause(criteria.Filter);
            }

            SecurityGeneratorNumberEntity entity = SecurityGeneratorNumberEntity.GetInstance();
            string sql = entity.GetSelectTopFrom(criteria.limit, criteria.page,  criteria.orderby.StringToDbField(), criteria.orderbytag, sqlWhere);

            string err = null;
            try
            {
                list = repository.FromSql(sql).ToArray();
            }
            catch (System.Exception ex)
            {
                err = ex.Message;
            }


            if (list != null && list.Length > 0)
            {
                sql = entity.GetSelectCountFrom(sqlWhere);
                count = (int)repository.ExecuteScalar(sql);
            }

            data.Limit = criteria.limit;
            data.Page = criteria.page;
            data.Datas = list;
            data.Total = count;
            //data.Sql = sql;
            data.ErrorMessage = err;
            return data;
        }

        [PermissionOperate(name: SecurityPermissionPolicy.SecurityGeneratorNumber, operate: Operate.Print)]
        public dynamic PrintBySearchCriteria(SecurityGeneratorNumberSearchCriteria criteria)
        {
            string sqlWhere = string.Empty;
            List<TemplateHeader> headers = new List<TemplateHeader>();

            Dictionary<string, Dictionary<string, object>> mappings = new Dictionary<string, Dictionary<string, object>>();
            Dictionary<string, object> validDic = new Dictionary<string, object>();
            foreach (string v in YesNoPolicy.GetInstance().GetValues())
            {
                validDic.Add(v, YesNoPolicy.GetInstance().ComposeMessage(v, service.Locale));
            }
            mappings.Add(SecurityGeneratorNumberEntity.REFRESH_PERIOD, validDic);

            List<string> searCriteria = criteria.PackSearchCriteriaDisplay(ref headers, ref sqlWhere, mappings);

            SecurityGeneratorNumberEntity entity = SecurityGeneratorNumberEntity.GetInstance();
            string sql = entity.GetSelectFrom() + " where 1=1 " + sqlWhere;

            SecurityGeneratorNumberEntity[] list = repository.FromSql(sql).ToArray();

            return new DataToExcelHelper<SecurityGeneratorNumberEntity>(service).ToExcel(criteria.ReportName, criteria.ReportName, searCriteria, headers.ToArray(), list, mappings);

        }

        [PermissionOperate(name: SecurityPermissionPolicy.SecurityGeneratorNumber, operate: Operate.Insert)]
        [UnitOfWork]
        public SecurityGeneratorNumberEntity Insert(SecurityGeneratorNumberEntity data)
        {
            throw new NotImplementedException();
        }

        [PermissionOperate(name: SecurityPermissionPolicy.SecurityGeneratorNumber, operate: Operate.Update)]
        [UnitOfWork]
        public SecurityGeneratorNumberEntity Update(SecurityGeneratorNumberEntity data)
        {
            SecurityGeneratorNumberEntity entity = repository.Entities.Where(x => x.GeneratorId == data.GeneratorId).FirstOrDefault()!;
            if (entity == null)
            {
                throw new ValidatedException("记录不存在.");
            }

            entity.RefreshPeriod = data.RefreshPeriod;
            entity.NextId = data.NextId;
            entity.Format = data.Format;

            repository.UpdateNow(entity);

            return entity;
        }


        [PermissionOperate(name: SecurityPermissionPolicy.SecurityGeneratorNumber, operate: Operate.Delete)]
        [UnitOfWork]
        public void Delete(int key)
        {
            SecurityGeneratorNumberEntity entity = repository.Entities.Where(x => x.GeneratorId == key).FirstOrDefault()!;
            if (entity == null)
            {
                throw new ValidatedException("记录不存在.");
            }

            repository.DeleteNow(entity);
        }


        public string GetNo(string systemId, string subsystemId)
        {
            return GetNo(systemId, subsystemId, null);
        }

        public string GetNo(string systemId, string subsystemId, string prefix)
        {
            return GetNo(systemId, subsystemId, prefix, null, null);
        }

        public string GetNo(string systemId, string subsystemId, string prefix, string refreshPeriod, string format)
        {
            SecurityGeneratorNumberEntity number = null;

            if (!string.IsNullOrEmpty(systemId) && !string.IsNullOrEmpty(subsystemId))
            {
                SecurityGeneratorNumberEntity[] tps = repository.Entities.Where(x => x.SystemId == systemId && x.SubsystemId == subsystemId).ToArray();

                if (tps != null && tps.Length > 0 && !string.IsNullOrEmpty(prefix))
                {
                    tps = tps.Where(x => x.Prefix == prefix).ToArray();
                }

                if (tps != null && tps.Length > 0) number = tps[0];
            }

            if (number == null)
            {
                number = new SecurityGeneratorNumberEntity();

                number.SystemId = string.IsNullOrEmpty(systemId) ? string.Empty : systemId;
                number.SubsystemId = string.IsNullOrEmpty(subsystemId) ? string.Empty : subsystemId;

                number.Prefix = string.IsNullOrEmpty(prefix) ? string.Empty : prefix;
                number.RefreshPeriod = string.IsNullOrEmpty(refreshPeriod) ? YesNoPolicy.YES : refreshPeriod;
                number.Format = string.IsNullOrEmpty(format) ? "yyMMdd000000" : format;
                number.LastGeneratorDate = DateTime.Now;
                number.NextId = 2;

                repository.InsertNow(number);
            }
            else
            {
                number.NextId += 1;

                number.LastGeneratorDate = DateTime.Now;
                repository.UpdateNow(number);
            }

            format = number.Format;

            if (number.LastGeneratorDate.Date.Subtract(DateTime.Now.Date).TotalDays != 0 && number.RefreshPeriod == YesNoPolicy.YES)
            {
                number.NextId = 1;
            }

            string temp = format.Replace("0", "").Replace("yyyy", DateTime.Now.ToString("yyyy"), StringComparison.OrdinalIgnoreCase).Replace("yy", DateTime.Now.ToString("yy"), StringComparison.OrdinalIgnoreCase)
                .Replace("MM", DateTime.Now.ToString("MM"), StringComparison.OrdinalIgnoreCase).Replace("dd", DateTime.Now.ToString("dd"));

            string zero = format.Replace("y", "").Replace("Y", "").Replace("M", "").Replace("m", "").Replace("d", "").Replace("D", "");
            string code = number.Prefix + temp + string.Format("{0:" + zero + "}", number.NextId - 1);

            Int64 max = Convert.ToInt64(zero.Replace("0", "9"));
            if (max == number.NextId)
            {
                throw new Exception("系统编号已达到最大值.");
            }

            return code;
        }

        public int GetNextId(string systemId, string subsystemId)
        {
            return GetNextId(systemId, subsystemId, null);
        }

        public int GetNextId(string systemId, string subsystemId, string prefix)
        {
            return GetNextId(systemId, subsystemId, prefix, null);
        }

        public int GetNextId(string systemId, string subsystemId, string prefix, string format)
        {
            return GetNextId(systemId, subsystemId, prefix, format, 1);
        }

        public int GetNextId(string systemId, string subsystemId, string prefix, string format, int length)
        {
            SecurityGeneratorNumberEntity number = null;

            if (!string.IsNullOrEmpty(systemId) && !string.IsNullOrEmpty(subsystemId))
            {
                SecurityGeneratorNumberEntity[] tps = repository.DetachedEntities.Where(x => x.SystemId == systemId && x.SubsystemId == subsystemId).ToArray();

                if (tps != null && tps.Length > 0 && !string.IsNullOrEmpty(prefix))
                {
                    tps = tps.Where(x => x.Prefix == prefix).ToArray();
                }

                if (tps != null && tps.Length > 0) number = tps[0];
            }

            if (number == null)
            {
                number = new SecurityGeneratorNumberEntity();

                number.SystemId = string.IsNullOrEmpty(systemId) ? string.Empty : systemId;
                number.SubsystemId = string.IsNullOrEmpty(subsystemId) ? string.Empty : subsystemId;

                number.Prefix = string.IsNullOrEmpty(prefix) ? string.Empty : prefix;
                number.Format = string.IsNullOrEmpty(format) ? "yyMMdd000000" : format;
                number.LastGeneratorDate = DateTime.Now;
                number.NextId = 1 + length;
                number.RefreshPeriod = YesNoPolicy.NO;

                repository.Insert(number);
            }
            else
            {

                number.NextId = number.NextId + length;

                if (number.LastGeneratorDate.Date.Subtract(DateTime.Now.Date).TotalDays != 0 && number.RefreshPeriod == YesNoPolicy.YES)
                {
                    number.NextId = 1 + length;
                }

                number.LastGeneratorDate = DateTime.Now;
                repository.Update(number);
            }

            string zero = number.Format.Replace("y", "").Replace("Y", "").Replace("M", "").Replace("m", "").Replace("d", "").Replace("D", "");

            Int64 max = Convert.ToInt64(zero.Replace("0", "9"));
            if (max == number.NextId - length)
            {
                throw new Exception("系统编号已达到最大值.");
            }

            return number.NextId - length - 1;
        }

    }
}
