
//--------------------------------------------------------------------
//     此代码由liquid模板自动生成  byzhouhang 20240909
//     生成时间 2026-03-10 06:17:28Z 
//     对此文件的更改可能会导致不正确的行为，并且如果重新生成代码，这些更改将会丢失。
//--------------------------------------------------------------------
using IRaCIS.Core.Application.Interfaces;
using IRaCIS.Core.Application.MassTransit.Command;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Infrastructure.Extention;
using MassTransit;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;

namespace IRaCIS.Core.Application.Service;
	
/// <summary>
/// 分割
/// </summary>
/// <param name="_segmentationRepository"></param>
/// <param name="_mapper"></param>
/// <param name="_userInfo"></param>
/// <param name="_localizer"></param>
[ ApiExplorerSettings(GroupName = "Reading")]
public class SegmentationService(IRepository<Segmentation> _segmentationRepository,
    IRepository<SegmentBinding> _segmentBindingRepository,
    IRepository<ReadingTaskQuestionAnswer> _readingTaskQuestionAnswerRepository,
      IRepository<VisitTask> _visitTaskRepository,
     IRepository<ReadingTableAnswerRowInfo> _readingTableAnswerRowInfoRepository,
     IRepository<ReadingTableQuestionAnswer> _readingTableQuestionAnswerRepository,
    IRepository<Segment> _segmentRepository,
    IRepository<ReadingQuestionTrial> _readingQuestionTrialRepository,
    IRepository<ReadingTableQuestionTrial> _readingTableQuestionTrialRepository,
    IRepository<SegmentationVersion> _segmentationVersionRepository,
                                  IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer): BaseService, ISegmentationService
{

	
    /// <summary>
    /// 获取分割组
    /// </summary>
    /// <param name="inQuery"></param>
    /// <returns></returns>
	[HttpPost]
	public async Task<PageOutput<SegmentationView>>  GetSegmentationList(SegmentationQuery inQuery)
	{
			
		    var segmentationQueryable =_segmentationRepository
            .WhereIf(inQuery.SegmentationName.IsNotNullOrEmpty(),x=>x.SegmentationName.Contains(inQuery.SegmentationName))
            .WhereIf(inQuery.Id != null, x => x.Id == inQuery.Id)
            .WhereIf(inQuery.TrialId != null, x => x.TrialId == inQuery.TrialId)
            .WhereIf(inQuery.SeriesId != null, x => x.SeriesId == inQuery.SeriesId)
            .WhereIf(inQuery.StudyId != null, x => x.StudyId == inQuery.StudyId)
            .WhereIf(inQuery.SubjectId != null, x => x.SubjectId == inQuery.SubjectId)
            .WhereIf(inQuery.SubjectVisitId != null, x => x.SubjectVisitId == inQuery.SubjectVisitId)
            .WhereIf(inQuery.VisitTaskId != null, x => x.VisitTaskId == inQuery.VisitTaskId)
            .ProjectTo<SegmentationView>(_mapper.ConfigurationProvider);

            var pageList= await segmentationQueryable.ToPagedListAsync(inQuery);

        return pageList;
	}


    /// <summary>
    /// 新增修改分割组
    /// </summary>
    /// <param name="addOrEditSegmentation"></param>
    /// <returns></returns>
    [HttpPost]
    public async Task<IResponseOutput> AddOrUpdateSegmentation(SegmentationAddOrEdit addOrEditSegmentation)
    {

        if (addOrEditSegmentation.Id != null)
        {
           var data=  await  _segmentationRepository.FirstOrDefaultNoTrackingAsync(x => x.Id == addOrEditSegmentation.Id);
            if (addOrEditSegmentation.SEGUrl != data.SEGUrl)
            {
                addOrEditSegmentation.SEGUpdateTime = DateTime.Now;
            }
            else
            {
                addOrEditSegmentation.SEGUpdateTime = data.SEGUpdateTime;
            }

                await SaveSegmentationVersionAsync(new SaveSegmentationVersionAsyncInDto() { SegmentationId = addOrEditSegmentation.Id.Value, SEGUrl = addOrEditSegmentation.SEGUrl });
        }
        var entity = await _segmentationRepository.InsertOrUpdateAsync(addOrEditSegmentation, true);
        return ResponseOutput.Ok(entity.Id.ToString());
    }

    /// <summary>
    /// 添加新版本
    /// </summary>
    /// <param name="inDto"></param>
    /// <returns></returns>
    public async Task SaveSegmentationVersionAsync(SaveSegmentationVersionAsyncInDto inDto)
    {
        var data = await _segmentationRepository.FirstOrDefaultNoTrackingAsync(x => x.Id == inDto.SegmentationId);
        // 如果是新增或修改，记录一条版本信息
        var maxVersion = await _segmentationVersionRepository
            .Where(x => x.SegmentationId == data.Id)
            .OrderByDescending(x => x.Version)
            .FirstOrDefaultAsync();


        var startTime = maxVersion != null ? maxVersion.CreateTime :(data.SEGUpdateTime==null? DateTime.MinValue: data.SEGUpdateTime.Value);

        var segmentList = await _segmentRepository
            .Where(x=>x.CreateTime<= startTime && (!x.IsDeleted||x.DeletedTime> startTime))
          
            .Where(x => x.SegmentationId == inDto.SegmentationId).OrderBy(x=>x.SegmentNumber).IgnoreQueryFilters().ProjectTo<SegmentVersionData>(_mapper.ConfigurationProvider).ToListAsync();

        if (data.SEGUrl != string.Empty&&(inDto.SEGUrl!=data.SEGUrl||inDto.IsRestore))
        {
        

            var newVersion = maxVersion == null ? 1 : maxVersion.Version + 1;
          


            var versionEntity = new SegmentationVersion
            {
                SegmentationId = data.Id,
                Version = newVersion,
                SegmentationJson = data.SegmentationJson,
                SEGUrl = data.SEGUrl,
                FileSize = data.FileSize,
                SegmentList= segmentList,
                StartTime= startTime,
            };

            await _segmentationVersionRepository.AddAsync(versionEntity);

            await _segmentationRepository.SaveChangesAsync();
        }
       
    }


    /// <summary>
    /// 获取分割组历史版本
    /// </summary>
    /// <param name="inQuery"></param>
    /// <returns></returns>
    [HttpPost]
    public async Task<PageOutput<SegmentationVersionView>> GetSegmentationVersionList(SegmentationVersionQuery inQuery)
    {
        var versionQueryable = _segmentationVersionRepository
            .Where(x => x.SegmentationId == inQuery.SegmentationId)
            .ProjectTo<SegmentationVersionView>(_mapper.ConfigurationProvider);
        var defalutSortArray = new string[] { nameof(SegmentationVersion.Version) + " desc" };
        var pageList = await versionQueryable.ToPagedListAsync(inQuery, defalutSortArray);

        return pageList;
    }

    /// <summary>
    /// 恢复分割组历史版本
    /// </summary>
    /// <param name="inDto"></param>
    /// <returns></returns>
    [HttpPost]
    public async Task<IResponseOutput> RestoreSegmentationVersion(RestoreSegmentationVersionInDto inDto)
    {
        var version = await _segmentationVersionRepository.Where(x => x.Id == inDto.VersionId && x.SegmentationId == inDto.SegmentationId).FirstNotNullAsync();
        var segmentation = await _segmentationRepository.Where(x => x.Id == inDto.SegmentationId).FirstNotNullAsync();

        await SaveSegmentationVersionAsync(new SaveSegmentationVersionAsyncInDto() { SegmentationId=inDto.SegmentationId,IsRestore=true,});
        await _segmentationRepository.UpdatePartialFromQueryAsync(x => x.Id == inDto.SegmentationId, t => new Segmentation
        {
            SegmentationJson = version.SegmentationJson,
            SEGUrl = version.SEGUrl,
            FileSize = version.FileSize,
        });

        var segmentList = _mapper.Map<List<Segment>>(version.SegmentList);

        await _segmentRepository.BatchDeleteNoTrackingAsync(x => x.SegmentationId == inDto.SegmentationId);
        await _segmentRepository.AddRangeAsync(segmentList);

        await _segmentationRepository.SaveChangesAsync();

        await DeleteBindingsAndAnswersAsync(inDto.SegmentationId, null);
        return ResponseOutput.Ok();
    }

    /// <summary>
    /// 删除分割组
    /// </summary>
    /// <param name="segmentationId"></param>
    /// <returns></returns>
    [HttpDelete("{segmentationId:guid}")]
    public async Task<IResponseOutput> DeleteSegmentation(Guid segmentationId)
	{
            await DeleteBindingsAndAnswersAsync(segmentationId, null);
			var success = await _segmentationRepository.DeleteFromQueryAsync(t => t.Id == segmentationId,true);
            return ResponseOutput.Ok();
	}


    /// <summary>
    /// 修改分割组的保存状态
    /// </summary>
    /// <param name="inDto"></param>
    /// <returns></returns>
    [HttpPost]
    public async Task<IResponseOutput> ChangeSegmentationSavedStatus(ChangeSegmentationSavedStatusInDto inDto)
    {
         await _segmentationRepository.UpdatePartialFromQueryAsync(x => x.Id == inDto.Id, t => new Segmentation
        {
            IsSaved = inDto.IsSaved
        });
        await _segmentationRepository.SaveChangesAsync();
        return ResponseOutput.Ok();
    }


    /// <summary>
    /// 获取分割
    /// </summary>
    /// <param name="inQuery"></param>
    /// <returns></returns>
    [HttpPost]
    public async Task<PageOutput<SegmentView>> GetSegmentList(SegmentQuery inQuery)
    {

        var segmentQueryable = _segmentRepository
           
            .WhereIf(inQuery.SegmentationId != null, x => x.SegmentationId == inQuery.SegmentationId)
             .WhereIf(inQuery.SegmentName.IsNotNullOrEmpty(), x => x.SegmentName.Contains(inQuery.SegmentName))
            .WhereIf(inQuery.VisitTaskId != null, x => x.VisitTaskId == inQuery.VisitTaskId)
                .WhereIf(inQuery.Id != null, x => x.Id == inQuery.Id)
                                    .ProjectTo<SegmentView>(_mapper.ConfigurationProvider);

        var pageList = await segmentQueryable.ToPagedListAsync(inQuery,nameof(SegmentView.SegmentNumber));

        return pageList;
    }


    /// <summary>
    /// 新增修改分割
    /// </summary>
    /// <param name="addOrEditSegment"></param>
    /// <returns></returns>
    [HttpPost]
    public async Task<IResponseOutput> AddOrUpdateSegment(SegmentAddOrEdit addOrEditSegment)
    {



        var entity = await _segmentRepository.InsertOrUpdateAsync(addOrEditSegment, true);

        return ResponseOutput.Ok(entity.Id.ToString());

    }

    /// <summary>
    /// 删除分割
    /// </summary>
    /// <param name="inQuery"></param>
    /// <returns></returns>
    [HttpDelete("{segmentId:guid}")]
    public async Task<IResponseOutput> DeleteSegment(Guid segmentId)
    {
        await DeleteBindingsAndAnswersAsync(null, segmentId);
        var success = await _segmentRepository.SoftDeleteFromQueryAsync(t => t.Id == segmentId, true);
        return ResponseOutput.Ok();
    }

    /// <summary>
    /// 锁定解锁分割
    /// </summary>
    /// <param name="inDto"></param>
    /// <returns></returns>
    public async Task<IResponseOutput> LockOrUnLockSegment(LockOrUnLockSegmentInDto inDto)
    {
        await _segmentRepository.UpdatePartialFromQueryAsync(x => x.Id == inDto.SegmentId, t => new Segment
        {
            IsLock = inDto.IsLock
        });
        await _segmentRepository.SaveChangesAsync();
        return ResponseOutput.Ok();
    }


    /// <summary>
    /// 获取分割绑定
    /// </summary>
    /// <param name="inQuery"></param>
    /// <returns></returns>
    [HttpPost]
    public async Task<PageOutput<SegmentBindingView>> GetSegmentBindingList(SegmentBindingQuery inQuery)
    {

        var segmentBindingQueryable = _segmentBindingRepository
             .WhereIf(inQuery.Id != null, x => x.Id == inQuery.Id)
             .WhereIf(inQuery.QuestionId != null, x => x.QuestionId == inQuery.QuestionId)
             .WhereIf(inQuery.RowId != null, x => x.RowId == inQuery.RowId)
             .WhereIf(inQuery.SegmentId != null, x => x.SegmentId == inQuery.SegmentId)
             .WhereIf(inQuery.SegmentationId != null, x => x.SegmentationId == inQuery.SegmentationId)
             .WhereIf(inQuery.TableQuestionId != null, x => x.TableQuestionId == inQuery.TableQuestionId)
             .WhereIf(inQuery.VisitTaskId != null, x => x.VisitTaskId == inQuery.VisitTaskId)
             .ProjectTo<SegmentBindingView>(_mapper.ConfigurationProvider);

        var pageList = await segmentBindingQueryable.ToPagedListAsync(inQuery);

        return pageList;
    }


    /// <summary>
    /// 新增修改分割绑定
    /// </summary>
    /// <param name="addOrEditSegmentBinding"></param>
    /// <returns></returns>
    public async Task<IResponseOutput> AddOrUpdateSegmentBinding(SegmentBindingAddOrEdit addOrEditSegmentBinding)
    {
    


        var entity = await _segmentBindingRepository.InsertOrUpdateAsync(addOrEditSegmentBinding, true);

        return ResponseOutput.Ok(entity.Id.ToString());

    }

    /// <summary>
    /// 删除分割
    /// </summary>
    /// <param name="segmentBindingId"></param>
    /// <returns></returns>
    [HttpDelete("{segmentBindingId:guid}")]
    public async Task<IResponseOutput> DeleteSegmentBinding(Guid segmentBindingId)
    {
        var success = await _segmentBindingRepository.DeleteFromQueryAsync(t => t.Id == segmentBindingId, true);
        return ResponseOutput.Ok();
    }

    /// <summary>
    /// 保存分割绑定和答案
    /// </summary>
    /// <param name="inDto"></param>
    /// <returns></returns>
    public async Task<IResponseOutput> SaveSegmentBindingAndAnswer(SaveSegmentBindingAndAnswerInDto inDto)
    {

        var taskinfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId)
            .FirstNotNullAsync();
        foreach (var item in inDto.BindingList)
        {
            // 处理绑定关系
            var binding = await _segmentBindingRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.QuestionId == item.QuestionId && x.RowId == item.RowId && x.TableQuestionId == item.TableQuestionId)
                .FirstOrDefaultAsync();
            if (binding == null)
            {
                if (item.SegmentationId != null && item.SegmentId != null)
                {
                    await _segmentBindingRepository.InsertFromDTOAsync(new SegmentBinding
                    {
                        VisitTaskId = inDto.VisitTaskId,
                        QuestionId = item.QuestionId,
                        RowId = item.RowId,
                        TableQuestionId = item.TableQuestionId,
                        SegmentId = item.SegmentId.Value,
                        SegmentationId = item.SegmentationId.Value,
                    });
                }
               
            }
            else
            {
                if (item.SegmentationId != null && item.SegmentId != null)
                {
                    await _segmentBindingRepository.UpdatePartialFromQueryAsync(x => x.Id == binding.Id, t => new SegmentBinding
                    {
                        SegmentId = item.SegmentId.Value,
                        SegmentationId = item.SegmentationId.Value,
                    });
                }
                else
                {
                    await _segmentBindingRepository.DeleteFromQueryAsync(x => x.Id == binding.Id);
                }
              
            }



            // 处理问题
            if (item.RowId != null && item.TableQuestionId != null&&item.QuestionId!=null)
            {
                var answer = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId&&x.QuestionId==item.QuestionId && x.RowId == item.RowId && x.TableQuestionId == item.TableQuestionId)
                  .FirstOrDefaultAsync();
                var rowinfo= await _readingTableAnswerRowInfoRepository.Where(x => x.Id==item.RowId)
                    .Include(x=>x.VisitTask)
                    .FirstNotNullAsync();
                if (answer != null)
                {
                    await _readingTableQuestionAnswerRepository.UpdatePartialFromQueryAsync(x => x.Id == answer.Id, t => new ReadingTableQuestionAnswer
                    {
                        Answer = item.Answer
                    });
                }
                else
                {
                    await _readingTableQuestionAnswerRepository.InsertFromDTOAsync(new ReadingTableQuestionAnswer
                    {
                        VisitTaskId = inDto.VisitTaskId,
                        RowId = item.RowId.Value,
                        QuestionId=item.QuestionId.Value,
                        TableQuestionId = item.TableQuestionId.Value,
                        Answer = item.Answer,
                        TrialId= rowinfo.VisitTask.TrialId,
                        RowIndex= rowinfo.RowIndex,
                    });
                }
            }
            else
            {

                var answer = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId &&x.ReadingQuestionTrialId==item.QuestionId)
                  .FirstOrDefaultAsync();

                if (answer != null)
                {
                    await _readingTaskQuestionAnswerRepository.UpdatePartialFromQueryAsync(x => x.Id == answer.Id, t => new ReadingTaskQuestionAnswer
                    {
                        Answer = item.Answer
                    });
                }
                else
                {
                    await _readingTaskQuestionAnswerRepository.InsertFromDTOAsync(new ReadingTaskQuestionAnswer
                    {
                       ReadingQuestionTrialId= item.QuestionId.Value,
                        ReadingQuestionCriterionTrialId=taskinfo.TrialReadingCriterionId,
                        TrialId= taskinfo.TrialId,
                        SubjectId= taskinfo.SubjectId,
                        VisitTaskId = inDto.VisitTaskId,
                        Answer=item.Answer,
                    });
                }
            }


           
        }

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

    /// <summary>
    /// 删除分割组和分割时的关联数据删除逻辑
    /// </summary>
    /// <param name="segmentationId"></param>
    /// <param name="segmentId"></param>
    /// <returns></returns>
    private async Task DeleteBindingsAndAnswersAsync(Guid? segmentationId, Guid? segmentId)
    {
        var bindingsQuery = _segmentBindingRepository
            .WhereIf(segmentationId != null, x => x.SegmentationId == segmentationId)
            .WhereIf(segmentId != null, x => x.SegmentId == segmentId);
            
        var bindings = await bindingsQuery.ToListAsync();

        foreach (var binding in bindings)
        {
            var visited = new HashSet<Guid>();
            
            // 处理问题
            if (binding.RowId != null && binding.TableQuestionId != null)
            {
                await _readingTableQuestionAnswerRepository.DeleteFromQueryAsync(x => x.VisitTaskId == binding.VisitTaskId && x.RowId == binding.RowId && x.TableQuestionId == binding.TableQuestionId);
                
                await DeleteDependentAnswersAsync(binding.TableQuestionId.Value, binding.VisitTaskId, binding.RowId, visited);
            }
            else if (binding.QuestionId != null)
            {
                await _readingTaskQuestionAnswerRepository.DeleteFromQueryAsync(x => x.VisitTaskId == binding.VisitTaskId && x.ReadingQuestionTrialId == binding.QuestionId);
                
                await DeleteDependentAnswersAsync(binding.QuestionId.Value, binding.VisitTaskId, null, visited);
            }
        }

        // 处理绑定关系
        if (segmentationId != null)
        {
            await _segmentBindingRepository.DeleteFromQueryAsync(x => x.SegmentationId == segmentationId);
        }
        else if (segmentId != null)
        {
            await _segmentBindingRepository.DeleteFromQueryAsync(x => x.SegmentId == segmentId);
        }
    }

    /// <summary>
    /// 递归清除依赖此问题的计算问题答案
    /// </summary>
    private async Task DeleteDependentAnswersAsync(Guid sourceQuestionId, Guid visitTaskId, Guid? rowId, HashSet<Guid> visited)
    {
        if (visited.Contains(sourceQuestionId)) return;
        visited.Add(sourceQuestionId);
        
        var sourceQuestionIdStr = sourceQuestionId.ToString();
        
        var dependentTableQuestions = await _readingTableQuestionTrialRepository
            .Where(x => x.DataSource == DataSources.Automatic && x.Type == "number" && x.CalculateQuestions.Contains(sourceQuestionIdStr))
            .Select(x => x.Id)
            .ToListAsync();
            
        foreach (var tableQuestionId in dependentTableQuestions)
        {
            if (rowId != null)
            {
                await _readingTableQuestionAnswerRepository.DeleteFromQueryAsync(x => x.VisitTaskId == visitTaskId && x.RowId == rowId && x.TableQuestionId == tableQuestionId);
            }
            await DeleteDependentAnswersAsync(tableQuestionId, visitTaskId, rowId, visited);
        }
        
        var dependentTaskQuestions = await _readingQuestionTrialRepository
            .Where(x => x.DataSource == DataSources.Automatic && x.Type == "number" && x.CalculateQuestions.Contains(sourceQuestionIdStr))
            .Select(x => x.Id)
            .ToListAsync();
            
        foreach (var taskQuestionId in dependentTaskQuestions)
        {
            await _readingTaskQuestionAnswerRepository.DeleteFromQueryAsync(x => x.VisitTaskId == visitTaskId && x.ReadingQuestionTrialId == taskQuestionId);
            await DeleteDependentAnswersAsync(taskQuestionId, visitTaskId, rowId, visited);
        }
    }

}



