//--------------------------------------------------------------------
//     此代码由liquid模板自动生成  byzhouhang 20240909
//     生成时间 2025-03-27 06:13:33Z 
//     对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
//--------------------------------------------------------------------
using IRaCIS.Core.Domain.Models;
using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Application.Interfaces;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Infrastructure.Extention;
using System.Threading.Tasks;
using IRaCIS.Core.Infra.EFCore;
using AutoMapper.Execution;
using System.Linq;
using IRaCIS.Core.Infrastructure;
using DocumentFormat.OpenXml.Office2010.Excel;
using MassTransit;
using NPOI.POIFS.Properties;
using Org.BouncyCastle.Crypto;
using Microsoft.AspNetCore.Http;
namespace IRaCIS.Core.Application.Service;


/// <summary>
/// 稽查文档
/// </summary>
/// <returns></returns>
[ApiExplorerSettings(GroupName = "FileRecord")]
public class AuditDocumentService(IRepository<AuditDocument> _auditDocumentRepository,
                                  IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer): BaseService
{

	/// <summary>
	/// 获取稽查文档
	/// </summary>
	/// <param name="inQuery"></param>
	/// <returns></returns>
	[HttpPost]
	public async Task<PageOutput<AuditDocumentView>> GetAuditDocumentList(AuditDocumentQuery inQuery)
	{
		var auditDocumentQueryable = _auditDocumentRepository
									.ProjectTo<AuditDocumentView>(_mapper.ConfigurationProvider);
		var pageList = await auditDocumentQueryable.ToPagedListAsync(inQuery);

		return pageList;
	}

	/// <summary>
	/// 修改稽查文档
	/// </summary>
	/// <param name="inDto"></param>
	/// <returns></returns>
	[HttpPost]
    public async Task<IResponseOutput> UpdateAuditDocument(AuditDocumentUpdateDto inDto)
    {
		AuditDocumentAddOrEdit addOrEdit = _mapper.Map<AuditDocumentAddOrEdit>(inDto);
		addOrEdit.IsUpdate = true;

		var result= await AddOrUpdateAuditDocument(addOrEdit);

        return ResponseOutput.Ok(result.Id);
    }

    /// <summary>
    /// 新增文件夹
    /// </summary>
    /// <param name="inDto"></param>
    /// <returns></returns>
    /// <exception cref="BusinessValidationFailedException"></exception>
    [HttpPost]
    public async Task<IResponseOutput> AddFolder(AuditDocumentAddOrEdit inDto)
    {

        if (await _auditDocumentRepository.AnyAsync(x => x.Name == inDto.Name && x.AuditDocumentTypeEnum == inDto.AuditDocumentTypeEnum && x.ParentId == inDto.ParentId))
        {
            throw new BusinessValidationFailedException(_localizer["AuditDocument_CanNotAddFolder"]);
        }

        List<AuditDocumentAddOrEdit> auditDocumentAddOrEdits = new List<AuditDocumentAddOrEdit>();

        auditDocumentAddOrEdits.Add(inDto);
        var result=   await AddAuditDocument(auditDocumentAddOrEdits);
        return ResponseOutput.Ok(result);
    }

    /// <summary>
    /// 新增稽查文档
    /// </summary>
    /// <param name="inDto"></param>
    /// <returns></returns>
    [HttpPost]
    public async Task<IResponseOutput> AddAuditDocument(List<AuditDocumentAddOrEdit> inDto)
	{
		List<Guid> resultData = new List<Guid>();
        inDto.ForEach(x => x.IsUpdate = false);
        await addData(inDto);

        async Task addData(List<AuditDocumentAddOrEdit> data)
		{
			foreach(var item in data)
			{
               var result= await AddOrUpdateAuditDocument(item);

				resultData.Add(result.Id);
                item.Children.ForEach(x => {
					x.ParentId = result.Id;
					x.IsUpdate = false;

                });

                if (item.Children.Count() > 0)
                {
                    await addData(item.Children);
                }
            }
		}

		return ResponseOutput.Ok(resultData);
    }



    /// <summary>
    /// 通用方法
    /// </summary>
    /// <param name="inDto"></param>
    private async  Task<AuditDocument> AddOrUpdateAuditDocument(AuditDocumentAddOrEdit inDto)
	{
		
			var alikeData = await _auditDocumentRepository.Where(x =>x.Id!=inDto.Id&& x.ParentId == inDto.ParentId&&x.Name==inDto.Name&&x.AuditDocumentTypeEnum==inDto.AuditDocumentTypeEnum).FirstOrDefaultAsync();
			if (alikeData != null)
			{
				if (inDto.AuditDocumentTypeEnum == AuditDocumentType.Folder)
				{
					if (inDto.IsUpdate)
					{
						throw new BusinessValidationFailedException(_localizer["AuditDocument_CanNotAddFolder"]);
					}
					else
					{
						return alikeData;
                    }
				}
				else
				{
                    var entityData = await _auditDocumentRepository.InsertOrUpdateAsync(inDto, true);
                    var historicalVersionIds = await _auditDocumentRepository.Where(x => x.MainFileId == alikeData.Id).OrderBy(x => x.Version).Select(x => x.Id).ToListAsync();
                    historicalVersionIds.Add(alikeData.Id);
                    int num = 1;

                    foreach (var item in historicalVersionIds)
                    {
                        await _auditDocumentRepository.UpdatePartialFromQueryAsync(item, x => new AuditDocument()
                        {
                            MainFileId = entityData.Id,
                            ParentId = null,
                            Version = num,
                            AuditDocumentTypeEnum = AuditDocumentType.HistoricalVersion
                        },true);
					    num++;
                    }

                    return entityData;
                }
			}
		

	   var entity = await _auditDocumentRepository.InsertOrUpdateAsync(inDto, true);
       return entity;
	}

	/// <summary>
	/// 获取面包屑导航
	/// </summary>
	/// <param name="inDto"></param>
	/// <returns></returns>
	[HttpPost]
	public async Task<List<AuditDocumentUpdateDto>> GetBreadcrumbData(GetBreadcrumbDataInDto inDto)
	{
		List<AuditDocumentUpdateDto> result=new List<AuditDocumentUpdateDto>();

		await findParent(result, inDto.Id);
        async Task findParent(List<AuditDocumentUpdateDto> datas, Guid id)
		{
            var data= await _auditDocumentRepository.Where(x => x.Id == id).ProjectTo<AuditDocumentUpdateDto>(_mapper.ConfigurationProvider).FirstNotNullAsync();
            datas.Add(data);
			if (data.ParentId != null)
			{
                await findParent(datas, data.ParentId.Value);
            }

        }

		result.Reverse();

        return result;

    }

    /// <summary>
    /// 获取文件树形结构 (传Id 根节点就是自己)
    /// </summary>
    /// <param name="inDto"></param>
    /// <returns></returns>
    [HttpPost]
	public async Task<PageOutput<AuditDocumentData>> GetAuditDocumentData(GetAuditDocumentDataInDto inDto)
	{

        var defalutSortArray = new string[] { nameof(AuditDocumentData.AuditDocumentTypeEnum), nameof(AuditDocumentData.Name) };
        if (inDto.SortField.IsNotNullOrEmpty())
        {
            defalutSortArray = new string[] { nameof(AuditDocumentData.AuditDocumentTypeEnum), inDto.SortField + (inDto.Asc ? " asc" : " desc") };
            inDto.SortField = string.Empty;
        }
		// 新取出来排序 然后再找子项
        var data=  (await _auditDocumentRepository
			.Where(x=>x.AuditDocumentTypeEnum!=AuditDocumentType.HistoricalVersion)
			.WhereIf(inDto.IsAuthorization!=null,x=>x.IsAuthorization==inDto.IsAuthorization)
			.ProjectTo<AuditDocumentData>(_mapper.ConfigurationProvider).ToPagedListAsync(new PageInput() { 
			 PageIndex=1,
			 PageSize=999999,
			}, defalutSortArray) ).CurrentPageData.ToList();
       
		
	
        if (inDto.Name.IsNotNullOrEmpty())
		{
            List<Guid> findIds = new List<Guid>();
            var findData = data.Where(x => x.Name.Contains(inDto.Name)).Select(x => x.Id.Value).ToList();
            GetParentId(findIds, findData, data);
            findIds.AddRange(findData);

			data = data.Where(x => findIds.Distinct().Contains(x.Id.Value)).ToList();

        }


		var query = data
            .WhereIf(inDto.SelfId != null, x => inDto.SelfId == x.Id)
            .WhereIf(inDto.Id != null, x => inDto.Id == x.ParentId)
			.WhereIf(inDto.Id == null&& inDto.SelfId == null, x => x.ParentId == null);



		PageOutput<AuditDocumentData> result = new PageOutput<AuditDocumentData>()
		{
			PageIndex = inDto.PageIndex,
			PageSize = inDto.PageSize,
			TotalCount = query.Count(),
        };
        var root = query
            .Skip(inDto.PageSize * (inDto.PageIndex - 1)).Take(inDto.PageSize).ToList();

        foreach (var item in root)
		{
            GetChildren(item, data);

        }
		result.CurrentPageData = root;
		return result;

    }

	private void GetParentId(List<Guid> parentIds, List<Guid> ids, List<AuditDocumentData> dataList)
	{
        var parentid = dataList.Where(x => ids.Contains(x.Id.Value) && x.ParentId != null).Select(x => x.ParentId.Value).ToList();

		if (parentid.Count() > 0)
		{
            parentIds.AddRange(parentid);

            GetParentId(parentIds, parentid, dataList);
        }
      
    }

	private void GetChildren(AuditDocumentData item, List<AuditDocumentData> dataList)
    {
        item.Children = dataList.Where(x => x.ParentId == item.Id).ToList();
        foreach (var x in item.Children)
        {
            GetChildren(x, dataList);
        }
    }

    /// <summary>
    /// 删除稽查文档
    /// </summary>
    /// <param name="inDto"></param>
    /// <returns></returns>
    [HttpPost]
    public async Task<IResponseOutput> DeleteAuditDocument(DeleteAuditDocumentInDto inDto)
	{
		var data = await _auditDocumentRepository.Select(x => new DeleteAudit (){
			Id=x.Id,
			ParentId= x.ParentId, 
			MainFileId= x.MainFileId 
		}).ToListAsync();

		List<Guid> DeleteId= inDto.Ids;

        finId(inDto.Ids, data);

        void finId(List<Guid> deletids, List<DeleteAudit> deletes)
		{
			DeleteId.AddRange(deletids);

			var temp = deletes.Where(x =>(x.ParentId!=null&& deletids.Contains(x.ParentId.Value))||(x.MainFileId!=null&& deletids.Contains(x.MainFileId.Value))).Select(x => x.Id).ToList();
			if (temp.Count() > 0)
			{
				finId(temp, deletes);
            }
        }

		DeleteId = DeleteId.Distinct().ToList();
		var mainFileId=await _auditDocumentRepository.Where(x => DeleteId.Contains(x.Id)&&x.MainFileId!=null).Select(x => x.MainFileId).Distinct().ToListAsync();
        var success = await _auditDocumentRepository.DeleteFromQueryAsync(t => DeleteId.Distinct().Contains(t.Id), true);

		foreach (var item in mainFileId)
		{
			var historicalVersionList = await _auditDocumentRepository.Where(x => x.MainFileId == item).OrderBy(x=>x.Version).ToListAsync();

			var num = 1;
			foreach (var historical in historicalVersionList)
			{
                await _auditDocumentRepository.UpdatePartialFromQueryAsync(historical.Id, x => new AuditDocument()
                {
                    Version = num,
                }, true);
                num++;
            }

          

        }


        return ResponseOutput.Ok();


    }

	/// <summary>
	/// 移动文件或者文件夹 到其他文件夹
	/// </summary>
	/// <returns></returns>
	[HttpPost]
	public async Task<IResponseOutput> MovieFileOrFolder(MovieFileOrFolderInDto inDto)
    {

        var data = await _auditDocumentRepository.Select(x => new DeleteAudit()
        {
            Id = x.Id,
            ParentId = x.ParentId,
            AuditDocumentTypeEnum = x.AuditDocumentTypeEnum,
            MainFileId = x.MainFileId
        }).ToListAsync();

		foreach (var id in inDto.Ids)
		{
            var file = data.Where(x => x.Id == id).FirstOrDefault();
            if (file.AuditDocumentTypeEnum == AuditDocumentType.Folder)
            {
                if (finChild(new List<Guid> { id }, inDto.ParentId, data))
                {
                    throw new BusinessValidationFailedException(_localizer["AuditDocument_CanNotMove"]);
                }
            }
        }

        bool finChild(List<Guid> ids, Guid ChildId, List<DeleteAudit> data)
        {
            var child = data.Where(x => x.ParentId != null && ids.Contains(x.ParentId.Value)).ToList();
            if (child.Count() == 0)
            {
                return false;
            }
            else if (child.Any(x => x.Id == ChildId))
            {
                return true;
            }
            else
            {
                var newids = child.Select(x => x.Id).ToList();

                return finChild(newids, ChildId, data);

            }
        }

        foreach (var id in inDto.Ids)
		{
            await _auditDocumentRepository.UpdatePartialFromQueryAsync(id, x => new AuditDocument()
            {
                ParentId = inDto.ParentId
            });

            await _auditDocumentRepository.SaveChangesAsync();
        }
		
        return ResponseOutput.Ok();
    }

    /// <summary>
    /// 复制文件或者文件夹
    /// </summary>
    /// <param name="inDto"></param>
    /// <returns></returns>
    [HttpPost]
	public async Task<IResponseOutput> CopyFileOrFolder(MovieFileOrFolderInDto inDto)
    {

		foreach (var item in inDto.Ids)
		{
          var data =  (await GetAuditDocumentData(new GetAuditDocumentDataInDto()
            {
                SelfId =item,
                
				PageIndex=1,
				PageSize= 1000
            })).CurrentPageData;

            List<AuditDocumentAddOrEdit> auditDocumentAddOrEdits = _mapper.Map<List<AuditDocumentAddOrEdit>>(data);
            auditDocumentAddOrEdits.ForEach(x => {
                x.IsUpdate = false;
                x.Id = null;
                x.ParentId = inDto.ParentId;
            });
            await addData(auditDocumentAddOrEdits);
        }

        async Task addData(List<AuditDocumentAddOrEdit> data)
        {
            foreach (var item in data)
            {
                item.Id = null;
                var result = await AddOrUpdateAuditDocument(item);

                item.Children.ForEach(x => {
                    x.ParentId = result.Id;
                    x.IsUpdate = false;
                    x.Id = null;
                });

                if (item.Children.Count() > 0)
                {
                    await addData(item.Children);
                }
            }
        }
        return ResponseOutput.Ok();
    }

    /// <summary>
    /// 获取历史版本
    /// </summary>
    /// <param name="inDto"></param>
    /// <returns></returns>
    [HttpPost]
	public async Task<List<HistoricalVersionDto>> GetHistoricalVersion(GetHistoricalVersionInDto inDto)
	{

		List< HistoricalVersionDto > result=new List<HistoricalVersionDto>();

		result = await _auditDocumentRepository.Where(x => x.MainFileId == inDto.Id).ProjectTo<HistoricalVersionDto>(_mapper.ConfigurationProvider).OrderByDescending(x => x.Version).ToListAsync();
	    var	 currentData = await _auditDocumentRepository.Where(x => x.Id == inDto.Id).ProjectTo<HistoricalVersionDto>(_mapper.ConfigurationProvider).FirstNotNullAsync();
		currentData.IsCurrentVersion = true;

        result.Insert(0, currentData);

		return result;
	}

	/// <summary>
	/// 把历史版本设置为当前版本
	/// </summary>
	/// <returns></returns>
	[HttpPost]
	public async Task<IResponseOutput> SetCurrentVersion(SetCurrentVersionInDto inDto) 
	{
        var file = await _auditDocumentRepository.Where(x => x.Id == inDto.Id).FirstNotNullAsync();
		if (file.AuditDocumentTypeEnum != AuditDocumentType.HistoricalVersion)
		{
            throw new BusinessValidationFailedException(_localizer["AuditDocument_CanNotSetCurrentVersion"]);
        }

		var mainFile = await _auditDocumentRepository.Where(x => x.Id == file.MainFileId).FirstNotNullAsync();

		var historicalVersionIds= await _auditDocumentRepository.Where(x => x.MainFileId == mainFile.Id&&x.Id!=inDto.Id).OrderBy(x=>x.Version).Select(x=>x.Id).ToListAsync();

		historicalVersionIds.Add(mainFile.Id);
        await _auditDocumentRepository.UpdatePartialFromQueryAsync(inDto.Id, x => new AuditDocument() { 
		  MainFileId=null,
		  ParentId= mainFile.ParentId,
		  AuditDocumentTypeEnum=AuditDocumentType.File,
        });

		int num = 1;
		foreach (var item in historicalVersionIds)
		{
            await _auditDocumentRepository.UpdatePartialFromQueryAsync(item, x => new AuditDocument()
            {
                MainFileId = inDto.Id,
                ParentId = null,
				Version=num,
				AuditDocumentTypeEnum= AuditDocumentType.HistoricalVersion
            });
			num++;
        }

		await _auditDocumentRepository.SaveChangesAsync();


        return ResponseOutput.Ok();

    }

	/// <summary>
	/// 设置是否授权
	/// </summary>
	/// <param name="inDto"></param>
	/// <returns></returns>
	[HttpPost]
	public async Task<IResponseOutput> SetIsAuthorization(SetIsAuthorizationInDto inDto)
	{
		var data = await _auditDocumentRepository.Select(x => new DeleteAudit()
		{
			Id = x.Id,
			ParentId = x.ParentId,
			MainFileId = x.MainFileId
		}).ToListAsync();

		List<Guid> allid = new List<Guid>();
		findChild(allid, inDto.Ids, data);
        if (inDto.IsAuthorization)
        {
            findParent(allid, inDto.Ids, data);
        }
        allid= allid.Distinct().ToList();
        await _auditDocumentRepository.UpdatePartialFromQueryAsync(t => allid.Contains(t.Id), x => new AuditDocument() { 
		
			IsAuthorization = inDto.IsAuthorization
        });
		await _auditDocumentRepository.SaveChangesAsync();
		return ResponseOutput.Ok();

        void findParent(List<Guid> allId, List<Guid> current, List<DeleteAudit> data)
        {
            allId.AddRange(current);
            var parent =  data.Where(x => current.Contains(x.Id)).Select(x => x.ParentId).Where(x=>x!=null).Select(x=>(Guid)x).ToList();
       
            if (parent.Count() > 0)
            {


                findParent(allId, parent, data);

            }
        }

        void findChild(List<Guid> allId,List<Guid> current, List<DeleteAudit>  data)
		{
			allId.AddRange(current);

			var child = data.Where(x =>(x.ParentId!=null&& current.Contains(x.ParentId.Value))||(x.MainFileId!=null&&current.Contains(x.MainFileId.Value))).Select(x => x.Id).ToList();
			if (child.Count() > 0)
			{
			

                findChild(allId, child, data);

            }

        }
    }

}