using MapsterMapper;
using Microsoft.AspNetCore.Mvc;
using XF.Domain.Authentications;
using XF.Domain.Repository;
using Hotline.Application.Planlibrary;
using Hotline.Share.Dtos.Planlibrary;
using SqlSugar;
using Hotline.Planlibrary;
using XF.Domain.Exceptions;
using Hotline.Share.Dtos;
using Hotline.Share.Tools;
using Hotline.Share.Enums.Planlibrary;
using Hotline.Application.ExportWord;
using Hotline.Application.Tools;
using Hotline.Share.Enums.Article;
using XF.Utility.EnumExtensions;
using Hotline.Share.Dtos.Order;
using Hotline.Application.ExportExcel;
using Hotline.Api.Filter;

namespace Hotline.Api.Controllers
{
    /// <summary>
    /// 预案库
    /// </summary>
    public class PlanController : BaseController
    {


        #region 注入

        private readonly IMapper _mapper;
        private readonly ISessionContext _sessionContext;
        private readonly IPlanApplication _planApplication;
        private readonly IRepository<PlanType> _planTypeRepository;
        private readonly IRepository<PlanList> _planListRepository;
        private readonly IRepository<PlanCollect> _planCollectRepository;
        private readonly IWordHelperService _wordHelperService;
        private readonly IExportApplication _exportApplication;

        public PlanController(
           IMapper mapper,
           ISessionContext sessionContext,
           IPlanApplication planApplication,
           IRepository<PlanType> planTypeRepository,
           IRepository<PlanList> planListRepository,
           IRepository<PlanCollect> planCollectRepository,
           IWordHelperService wordHelperService,
           IExportApplication exportApplication)
        {
            _mapper = mapper;
            _sessionContext = sessionContext;
            _planApplication = planApplication;
            _planTypeRepository = planTypeRepository;
            _planListRepository = planListRepository;
            _planCollectRepository = planCollectRepository;
            _wordHelperService = wordHelperService;
            _exportApplication = exportApplication;
        }

        #endregion

        #region 预案库类型管理

        /// <summary>
        /// 获取列表层级分类
        /// </summary>
        /// <param name="IsEnable">是否启用</param>
        /// <returns></returns>
        [HttpGet("type/treelist")]
        public async Task<List<PlanTypeDto>> QueryAllTreeList(bool? IsEnable)
        {
            return await _planTypeRepository.Queryable()
                .WhereIF(IsEnable.HasValue, x => x.IsEnable == IsEnable)
                .Where(x => SqlFunc.Subqueryable<PlanTypeOrg>().Where(to => to.TypeId == x.Id).Any() ||
                SqlFunc.Subqueryable<PlanTypeOrg>().Where(to => to.TypeId == x.Id).NotAny()
                )
                .Select(x => new PlanTypeDto()
                {
                    Id = x.Id.SelectAll()
                }
                )
                .OrderBy(x => x.Sort).ToTreeAsync(it => it.children, it => it.ParentId, null, it => it.Id);
        }

        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("type/add")]
        public async Task<string> AddType([FromBody] AddPlanTypeDto dto)
        {
            return await _planApplication.AddTypeAsync(dto, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 编辑
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut("type/update")]
        public async Task UpdateType([FromBody] UpdatePlanTypeDto dto)
        {
            await _planApplication.UpdateTypeAsync(dto, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 查询详情
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        [HttpGet("type/info/{Id}")]
        public async Task<PlanType> GetType(string Id)
        {
            var types = await _planTypeRepository.Queryable()
                .Includes(x => x.PlanTypeOrgs)   // 填充子对象
                .Where(x => x.Id == Id)
                .FirstAsync(HttpContext.RequestAborted);
            if (types is null)
                throw UserFriendlyException.SameMessage("查询失败！");
            return types;
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        [HttpDelete("type/remove/{Id}")]
        public async Task RemoveType(string Id)
        {
            await _planApplication.RemoveTypeAsync(Id, HttpContext.RequestAborted);
        }

        #endregion

        #region 预案库管理

        /// <summary>
        /// 预案库分类列表
        /// </summary>
        /// <param name="IsEnable"></param>
        /// <returns></returns>
        [HttpGet("list/treelist")]
        public async Task<List<PlanTypeDto>> QueryAllPlanTypeTreeList(bool? IsEnable)
        {
            return await _planTypeRepository.Queryable()
                .WhereIF(IsEnable.HasValue, x => x.IsEnable == IsEnable)
                .Where(x => SqlFunc.Subqueryable<PlanTypeOrg>().Where(to => to.TypeId == x.Id).Any() ||
                            SqlFunc.Subqueryable<PlanTypeOrg>().Where(to => to.TypeId == x.Id).NotAny()
                )
                .Select(x => new PlanTypeDto()
                {
                    Id = x.Id.SelectAll(),
                    PlanNum = SqlFunc.Subqueryable<PlanRelationType>().LeftJoin<PlanList>((kr, k) => kr.PlanId == k.Id)
                         .Where((kr, k) => kr.PlanTypeId == x.Id)
                         .DistinctCount(kr => kr.PlanId)
                }
                )
                .OrderBy(x => x.Sort).ToTreeAsync(it => it.children, it => it.ParentId, null, it => it.Id);
        }

        /// <summary>
        /// 预案库列表
        /// </summary>
        /// <param name="pagedDto"></param>
        /// <returns></returns>
        [HttpGet("list")]
        public async Task<PagedDto<PlanDataDto>> QueryAllPlanList([FromQuery] PlanListDto pagedDto)
        {
            return (await _planApplication.QueryAllPlanListAsync(pagedDto, HttpContext.RequestAborted)).ToPaged();
        }

        /// <summary>
        /// 预案库草稿
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("list/draft")]
        public async Task<string> PlanDraft([FromBody] AddPlanListDto dto)
        {
            dto.Status = EPlanStatus.NewDrafts;
            return await _planApplication.AddPlanAsync(dto, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 预案库草稿修改
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut("list/draftupdate")]
        public async Task UpdatePlanDraft([FromBody] UpdatePlanListDto dto)
        {
            dto.Status = EPlanStatus.NewDrafts;
            await _planApplication.UpdatePlanAsync(dto, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 预案库草稿到审核
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut("list/draftadd")]
        public async Task AddPlanDraft([FromBody] UpdatePlanListDto dto)
        {
            dto.ApplyStatus = EPlanApplyStatus.Add;
            dto.Status = EPlanStatus.OnShelf;
            await _planApplication.UpdatePlanAsync(dto, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 预案库草稿删除
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        [HttpDelete("list/draftremove/{Id}")]
        public async Task RemovePlanDraft(string Id)
        {
            UpdatePlanListDto dto = new UpdatePlanListDto();
            dto.ApplyStatus = EPlanApplyStatus.Delete;
            dto.Status = EPlanStatus.Auditing;
            dto.Id = Id;
            await _planApplication.RemovePlanAsync(dto, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 预案库删除到审核
        /// </summary>
        /// <param name="dtoDel"></param>
        /// <returns></returns>
        [HttpDelete("list/remove")]
        public async Task RemovePlan([FromBody] DelPlanListDto dtoDel)
        {
            UpdatePlanListDto dto = new UpdatePlanListDto();
            dto.ApplyStatus = EPlanApplyStatus.Delete;
            dto.Status = EPlanStatus.Auditing;
            dto.Id = dtoDel.Id;
            dto.ApplyReason = dtoDel.ApplyReason;
            await _planApplication.UpdatePlanAsync(dto, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 预案库新增到审核
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("list/add")]
        public async Task<string> AddPlan([FromBody] AddPlanListDto dto)
        {
            dto.ApplyStatus = EPlanApplyStatus.Add;
            dto.Status = EPlanStatus.Auditing;
            return await _planApplication.AddPlanAsync(dto, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 预案库编辑提交到审核
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut("list/update")]
        public async Task UpdatePlan([FromBody] UpdatePlanListDto dto)
        {
            dto.ApplyStatus = EPlanApplyStatus.Update;
            dto.Status = EPlanStatus.Auditing;
            await _planApplication.UpdatePlanAsync(dto, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 预案库上架
        /// </summary>
        /// <param name="Id">预案库ID</param>
        /// <returns></returns>
        [HttpGet("list/onshelf/{Id}")]
        public async Task OnshelfPlan(string Id)
        {
            UpdatePlanListDto dto = new UpdatePlanListDto();
            dto.Id = Id;
            dto.ApplyStatus = EPlanApplyStatus.Add;
            dto.Status = EPlanStatus.OnShelf;
            dto.OnShelfTime = DateTime.Now;
            await _planApplication.AuditPlanAsync(dto, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 预案库下架
        /// </summary>
        /// <param name="Id">预案库ID</param>
        /// <returns></returns>
        [HttpGet("list/offshelf/{Id}")]
        public async Task OffshelfPlan(string Id)
        {
            UpdatePlanListDto dto = new UpdatePlanListDto();
            dto.Id = Id;
            dto.ApplyStatus = EPlanApplyStatus.Offshelf;
            dto.Status = EPlanStatus.OffShelf;
            dto.OffShelfTime = DateTime.Now;

            await _planApplication.AuditPlanAsync(dto, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 预案库审核（新增、修改、删除）
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut("list/examin")]
        public async Task ExaminPlan([FromBody] AuditPlanListDto dto)
        {
            var plan = await _planListRepository.GetAsync(dto.Id);
            if (plan == null)
                throw UserFriendlyException.SameMessage("预案库查询失败");

            var planDto = _mapper.Map<UpdatePlanListDto>(plan);

            if (dto.State == 0)
            {//不同意
                planDto.Status = EPlanStatus.Revert;
            }
            else if (dto.State == 1)
            {//同意 
                if (planDto.ApplyStatus == EPlanApplyStatus.Add)
                {
                    planDto.Status = EPlanStatus.OnShelf;
                    planDto.OnShelfTime = DateTime.Now;
                }
                if (planDto.ApplyStatus == EPlanApplyStatus.Update)
                {
                    planDto.Status = EPlanStatus.OnShelf;
                    planDto.OnShelfTime = DateTime.Now;
                    planDto.UpdateTime = DateTime.Now;
                }
                if (planDto.ApplyStatus == EPlanApplyStatus.Offshelf)
                {
                    planDto.Status = EPlanStatus.OffShelf;
                    planDto.OffShelfTime = DateTime.Now;
                }
                if (planDto.ApplyStatus == EPlanApplyStatus.Delete)
                {
                    planDto.Status = EPlanStatus.Drafts;
                }
            }
            planDto.Id = dto.Id;
            planDto.ExaminTime = DateTime.Now;
            planDto.ExaminManId = _sessionContext.UserId;
            planDto.ExaminOrganizeId = _sessionContext.OrgId;
            planDto.ExaminOpinion = dto.ExaminOpinion;

            await _planApplication.AuditPlanAsync(planDto, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 预案库详情
        /// </summary>
        /// <param name="Id"></param>
        /// <param name="IsAddPv"></param>
        /// <returns></returns>
        [HttpGet("list/info")]
        public async Task<PlanInfoDto> GetPlan(string Id, bool IsAddPv)
        {
            return await _planApplication.GetPlanAsync(Id, IsAddPv, HttpContext.RequestAborted);
        }

        /// <summary>
        /// 预案库申请理由
        /// </summary>
        /// <param name="Id">预案库ID</param>
        /// <returns></returns>
        [HttpGet("list/reason/{Id}")]
        public async Task<PlanApplyReasonDto> ReasonPlan(string Id)
        {
            var reason = await _planListRepository.GetAsync(x => x.Id == Id);
            return _mapper.Map<PlanApplyReasonDto>(reason);
        }

        /// <summary>
        /// 预案库评分
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPut("list/score")]
        public async Task ScorePlan([FromBody] PvPlanListDto dto)
        {
            var collect = await _planCollectRepository.GetAsync(x => x.PlanId == dto.Id && x.CreatorId == _sessionContext.UserId);
            if (collect != null)
            {
                if (collect.Score > 0)
                    throw UserFriendlyException.SameMessage("当前知识已经评分");

                collect.Score = dto.Score;
                await _planCollectRepository.UpdateAsync(collect, HttpContext.RequestAborted);
            }
            else
            {
                collect = new PlanCollect();
                collect.PlanId = dto.Id;
                collect.Score = dto.Score;
                await _planCollectRepository.AddAsync(collect, HttpContext.RequestAborted);
            }

            //计算总分
            var sugar = _planCollectRepository.Queryable().Where(x => x.PlanId == dto.Id);
            var count = await sugar.CountAsync();
            var collects = await sugar.SumAsync(x => x.Score);
            var scoreTemp = collects / count;
            var plan = await _planListRepository.GetAsync(x => x.Id == dto.Id);
            if (plan != null)
            {
                plan.Score = decimal.Round(scoreTemp.Value, 1);
                await _planListRepository.UpdateAsync(plan, HttpContext.RequestAborted);
            }
        }

        /// <summary>
        /// 预案库查重
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("list/exist")]
        public async Task<bool> ExistPlan([FromBody] PlanExistDto dto)
        {
            var any = await _planListRepository.Queryable()
                .Where(x => x.Status == EPlanStatus.Auditing || x.Status >= EPlanStatus.OnShelf)
                .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Title.Equals(dto.Title))
                .WhereIF(!string.IsNullOrEmpty(dto.Content), x => x.Content.Equals(dto.Content))
                .WhereIF(!string.IsNullOrEmpty(dto.Id), x => x.Id != dto.Id)
                .AnyAsync();
            return any;
        }

        /// <summary>
        /// 预案库详情导出
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("list/info/export")]
		[LogFilterAlpha("导出日志")]
		public async Task<IActionResult> PlanInfoExport([FromBody] PlanInfoExportDto dto)
        {
            if (dto.Ids.Length > 1)
            {
                var streams = await _planApplication.PlanInfoListExportAsync(dto, HttpContext.RequestAborted);
                byte[] fileBytes = _wordHelperService.ConvertZipStream(streams);
                var name = DateTime.Now.ToString("yyyyMMddHHmmss");
                return File(fileBytes, "application/octet-stream", $"{name}.zip");
            }
            var info = await _planListRepository.GetAsync(dto.Ids[0]) ?? throw UserFriendlyException.SameMessage("预案不存在");
            return info.Content.HtmlToStream(dto.FileType).GetFileStreamResult(dto.FileType, info.Title, false);
        }

        /// <summary>
        /// 预案库列表导出
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        [HttpPost("export")]
        public async Task<IActionResult> GetPlanListExportAsync([FromBody] ExportExcelDto<PlanListDto> dto)
        {
            var items = (await _planApplication.QueryAllPlanListAsync(dto.QueryDto, HttpContext.RequestAborted)).Item2;
            return _exportApplication.GetExcelFile(dto, items, "预案明细导出");
        }


        /// <summary>
        /// 预案库列表页面枚举值
        /// </summary>
        /// <returns></returns>
        [HttpGet("list/status-data")]
        public Dictionary<string, dynamic> PlanStatus()
        {
            var tabStatusName = new List<KeyValuePair<int, string>>
            {
                new KeyValuePair<int, string>(3, "已上架"),
                new KeyValuePair<int, string>(4, "已下架"),
                new KeyValuePair<int, string>(1, "审核中"),
                new KeyValuePair<int, string>(7, "草稿"),
                new KeyValuePair<int, string>(-1, "全部")
            };

            var tabExamineName = new List<KeyValuePair<int, string>>
            {
                new KeyValuePair<int, string>(-1, "全部"),
                new KeyValuePair<int, string>(0, "新增审核"),
                new KeyValuePair<int, string>(1, "修改审核"),
                new KeyValuePair<int, string>(2, "删除审核")
            };

            var StatusName = new List<KeyValuePair<int, string>>
            {
                new KeyValuePair<int, string>(-1, "全部"),
                new KeyValuePair<int, string>(0, "待提交"),
                new KeyValuePair<int, string>(1, "审核中"),
                new KeyValuePair<int, string>(3, "已上架"),
                new KeyValuePair<int, string>(4, "已下架"),
                new KeyValuePair<int, string>(5, "审核不通过"),
                new KeyValuePair<int, string>(6, "已过期"),
                new KeyValuePair<int, string>(7, "草稿")
            };

            var ApplyStatusName = new List<KeyValuePair<int, string>>
            {
                new KeyValuePair<int, string>(-1, "全部"),
                new KeyValuePair<int, string>(0, "新增审核"),
                new KeyValuePair<int, string>(1, "修改审核"),
                new KeyValuePair<int, string>(2, "删除审核")
            };

            var ignoreFileType = EFileType.excel | EFileType.pdf;
            var items = EnumExts.GetDescriptions<EFileType>();
            var filteredDictionary = items
                 .Where(kvp => (ignoreFileType & (EFileType)kvp.Key) == 0)
                 .ToDictionary(kvp => kvp.Key, kvp => kvp.Value)
                 .ToList();

            return new Dictionary<string, dynamic>
            {
                { "fileType", filteredDictionary},
                { "tabStatusName", tabStatusName },
                { "tabExamineName", tabExamineName },
                { "StatusName", StatusName },
                { "ApplyStatusName", ApplyStatusName }
            };
        }

        #endregion

        #region 预案库检索

        /// <summary>
        /// 检索列表
        /// </summary>
        /// <param name="pagedDto"></param>
        /// <returns></returns>
        [HttpGet("search")]
        public async Task<PagedDto<PlanDataDto>> QueryOnShelfPlanList([FromQuery] PlanListDto pagedDto)
        {
            pagedDto.Status = EPlanStatus.OnShelf;
            return (await _planApplication.QueryAllPlanListAsync(pagedDto, HttpContext.RequestAborted)).ToPaged();
        }

        /// <summary>
        /// 检索列表前10
        /// </summary>
        /// <returns></returns>
        [HttpGet("search/top10")]
        public async Task<List<PlanPageViewDto>> QueryTop10PlanList()
        {
            return await _planListRepository.Queryable()
                .Take(10)
                .Where(x => x.Status == EPlanStatus.OnShelf)
                .Select(x => new PlanPageViewDto
                {
                    Id = x.Id,
                    Title = x.Title,
                    PageView = x.PageView
                })
                .OrderBy(x => x.PageView, OrderByType.Desc)
                .ToListAsync();
        }

        #endregion
    }
}
