using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.Service.Reading.Dto;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infra.EFCore.Common;
using MassTransit;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using MiniExcelLibs;
using System.Data;
using System.IO;
using System.Text;

namespace IRaCIS.Core.Application.Service.ReadingCalculate
{
    public class GeneralCalculateService(IRepository<ReadingTableQuestionAnswer> _readingTableQuestionAnswerRepository,
            IRepository<VisitTask> _visitTaskRepository,
               IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
                  ILogger<GeneralCalculateService> _logger,
            IRepository<ReadingTableQuestionTrial> _readingTableQuestionTrialRepository,
            IRepository<ReadingTableAnswerRowInfo> _readingTableAnswerRowInfoRepository,
            IRepository<ReadingQuestionTrial> _readingQuestionTrialRepository,
            IRepository<SubjectVisit> _subjectVisitRepository,
            IRepository<TumorAssessment_RECIST1Point1> _tumorAssessmentRepository,
            IRepository<ReadingTaskQuestionAnswer> _readingTaskQuestionAnswerRepository,
            IRepository<InspectionFile> _inspectionFileRepository,
             IOSSService oSSService, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, IGeneralCalculateService
    {

     


        /// <summary>
        /// 从上传文件中获取Datatable
        /// </summary>
        /// <returns></returns>
        public async Task<FileToDataTableDto> GetDataTableFromUpload(IFormFile file,string pathCode,Guid trialId)
        {

            FileToDataTableDto result=new FileToDataTableDto ();

            result.DataTable = new DataTable();
            var fileFolder = "Upload\\";
            if (!Directory.Exists(fileFolder))
            {
                Directory.CreateDirectory(fileFolder);
            }

            var fileName = DateTime.Now.ToString("yyyyMMddHHmmss") +
                           Path.GetExtension(file.FileName);
            var filePath = Path.Combine(fileFolder, fileName);

            var fileStream = new MemoryStream();
            try
            {
                using (var stream = new FileStream(filePath, FileMode.Create))
                {
                    file.CopyTo(stream);
                    await stream.CopyToAsync(fileStream);

                    result.SheetNames= stream.GetSheetNames();
                    stream.Position = 0;
                    result.DataTable = stream.QueryAsDataTable(useHeaderRow: false);
                }
            }
            catch (Exception)
            {
                File.Delete(filePath);
            }


            try
            {
                var ossRelativePath = await oSSService.UploadToOSSAsync(fileStream, "InspectionUpload/"+ pathCode, file.FileName);
                await _inspectionFileRepository.AddAsync(new InspectionFile() { FileName = file.FileName, RelativePath = ossRelativePath, TrialId = trialId });
            }
            catch (Exception)
            {

             
            }
          



            File.Delete(filePath);

            // 创建一个要删除的行集合
            var rowsToRemove = new System.Collections.Generic.List<DataRow>();

            // 遍历DataTable的每一行
            foreach (DataRow row in result.DataTable.Rows)
            {
                bool allEmpty = true;

                // 遍历每一列,检查值
                foreach (var item in row.ItemArray)
                {
                    if (item!=null&&!item.ToString().IsNullOrEmpty())
                    {
                        allEmpty = false;
                        break; // 只要有一个不为空,跳出循环
                    }
                }

                // 如果所有列都是空字符串,则添加到待删除的行集合中
                if (allEmpty)
                {
                    rowsToRemove.Add(row);
                }
            }

            // 移除标记为待删除的行
            foreach (var row in rowsToRemove)
            {
                result.DataTable.Rows.Remove(row);
            }
            return result;
        }

        /// <summary>
        /// 添加计算错误日志
        /// </summary>
        /// <param name="inDto"></param>
        /// <param name="lesionName"></param>
        /// <param name="lesionType"></param>
        /// <returns></returns>
        public async Task LogRecord(ReadingCalculateDto inDto, string lesionName, LesionType lesionType)
        {
            // 这里是记录日志 不需要国际化
            var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == inDto.TrialReadingCriterionId).Include(x => x.Trial).FirstNotNullAsync();
            var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Include(x => x.Subject).Include(x => x.DoctorUser).FirstNotNullAsync();

            //错误级别日志:项目、标准、受试者、阅片人、任务。输出其它既往新病灶数据:

            StringBuilder builder = new StringBuilder();
            builder.AppendLine($"");
            builder.AppendLine($"【项目】:【{criterionInfo.Trial.TrialCode}】");
            builder.AppendLine($"【项目Id】:【{criterionInfo.TrialId}】");
            builder.AppendLine($"【标准】:【{criterionInfo.CriterionName}】");
            builder.AppendLine($"【标准Id】:【{criterionInfo.Id}】");
            builder.AppendLine($"【受试者】:【{taskInfo.Subject.ShortName}】");
            builder.AppendLine($"【受试者Id】:【{taskInfo.Subject.Id}】");
            builder.AppendLine($"【阅片人】:【{taskInfo.DoctorUser.FirstName}】");
            builder.AppendLine($"【阅片人Id】:【{taskInfo.DoctorUser.Id}】");
            builder.AppendLine($"【任务】:【{taskInfo.TaskBlindName}】");
            builder.AppendLine($"【任务Id】:【{taskInfo.Id}】");
            builder.AppendLine($"【病灶类型】:【{lesionName}】");

            var lesionInfo = inDto.QuestionInfo.Where(x => x.LesionType == lesionType).FirstOrDefault();
            if (lesionInfo != null)
            {
                lesionInfo.TableRowInfoList.OrderBy(x => x.RowIndex).ForEach(x =>
                {
                    builder.AppendLine(@$"【病灶编号】:【{x.RowIndex.ToString()}】,
                                         【病灶长径】:【{x.TableQuestionList.Where(y => y.QuestionMark == QuestionMark.MajorAxis).Select(y => y.Answer).FirstIsNullReturnEmpty()}】,
                                         【病灶短径】:【{x.TableQuestionList.Where(y => y.QuestionMark == QuestionMark.ShortAxis).Select(y => y.Answer).FirstIsNullReturnEmpty()}】,
                                         【病灶状态】:【{x.TableQuestionList.Where(y => y.QuestionMark == QuestionMark.State).Select(y => y.Answer).FirstIsNullReturnEmpty()}】");

                });
            }

            _logger.LogError(builder.ToString());
        }


        /// <summary>
        /// 获取ReadingCalculateDto
        /// </summary>
        /// <param name="visitTaskId"></param>
        /// <returns></returns>
        public async Task<ReadingCalculateDto> GetReadingCalculateDto(Guid visitTaskId)
        {
            var visitTask = await _visitTaskRepository.Where(x => x.Id == visitTaskId).FirstNotNullAsync();

            var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == visitTask.TrialReadingCriterionId).FirstNotNullAsync();
            var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == (visitTask.SourceSubjectVisitId ?? default(Guid))).FirstOrDefaultAsync();

            var baseLineVisitId = await _subjectVisitRepository.Where(x => x.SubjectId == visitTask.SubjectId && x.IsBaseLine).Select(x => x.Id).FirstOrDefaultAsync();


            var rowInfoList = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == visitTaskId).ToListAsync();

            var baseLinetaskId = await _visitTaskRepository.Where(x => x.SourceSubjectVisitId == baseLineVisitId && x.TaskState == TaskState.Effect
            && x.TrialReadingCriterionId == visitTask.TrialReadingCriterionId
            && x.ArmEnum == visitTask.ArmEnum).Select(x => x.Id).FirstOrDefaultAsync();

            List<QuestionInfo> questionInfos = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == visitTask.TrialReadingCriterionId).Select(x => new QuestionInfo()
            {
                LesionType = x.LesionType,
                QuestionId = x.Id,
                QuesionName = x.QuestionName.LanguageName(x.QuestionEnName, _userInfo.IsEn_Us),
                OrderMark = x.OrderMark,
                QuestionType = x.QuestionType,
                ValueType = x.ValueType,
            }).ToListAsync();

            var questionAnswers = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == visitTaskId).Select(x => new
            {
                x.ReadingQuestionTrialId,
                x.Answer
            }).ToListAsync();

            var tableQuestion = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == visitTaskId).Include(x => x.ReadingTableQuestionTrial).Select(x => new TableQuestionInfo()
            {
                Answer = x.Answer,
                AnswerId = x.Id,
                QuestionMark = x.ReadingTableQuestionTrial.QuestionMark,
                TableQuestionId = x.TableQuestionId,
                QuestionId = x.QuestionId,
                QuestionType = x.ReadingQuestionTrial.QuestionType,
                RowIndex = x.RowIndex,
                RowId = x.RowId,
            }).ToListAsync();

            foreach (var item in questionInfos)
            {
                item.Answer = questionAnswers.Where(y => y.ReadingQuestionTrialId == item.QuestionId).Select(x => x.Answer).FirstOrDefault() ?? string.Empty;


                var thisItemRowInfo = rowInfoList.Where(x => x.QuestionId == item.QuestionId).ToList();

                var thisItemTableQuestions = tableQuestion.Where(x => x.QuestionId == item.QuestionId).ToList();

                item.TableRowInfoList = thisItemRowInfo.Select(x => new TableRowInfo()
                {
                    RowId = x.Id,
                    RowIndex = x.RowIndex,
                    MeasureData = x.MeasureData,
                    OtherMeasureData = x.OtherMeasureData,
                    FristAddTaskNum = x.FristAddTaskNum,
                    TableQuestionList = tableQuestion.Where(y => y.QuestionId == item.QuestionId && y.RowId == x.Id).ToList(),

                }).ToList();




            }

            ReadingCalculateDto readingData = new ReadingCalculateDto()
            {
                SubjectId = visitTask.SubjectId,
                TaskBlindName = visitTask.TaskBlindName,
                IsConvertedTask = await _visitTaskRepository.Where(x => x.Id == visitTaskId).Select(x => x.IsConvertedTask).FirstOrDefaultAsync(),
                BeforeConvertedTaskId = visitTask.BeforeConvertedTaskId,
                VisitTaskId = visitTaskId,
                SubjectVisitId = visitTask.SourceSubjectVisitId!.Value,
                QuestionInfo = questionInfos,
                CriterionId = visitTask.TrialReadingCriterionId,
                TrialId = visitTask.TrialId,
                IsAnalysisCreate = visitTask.IsAnalysisCreate,
                IsSelfAnalysis = visitTask.IsSelfAnalysis,
                IsBaseLine = subjectVisit!.IsBaseLine,
                DoctorUserId = visitTask.DoctorUserId,
                TrialReadingCriterionId = visitTask.TrialReadingCriterionId,
                BaseLineTaskId = baseLinetaskId,
                ArmEnum = visitTask.ArmEnum,
                VisitName = subjectVisit.VisitName,
                BlindName = subjectVisit.BlindName,
                VisitTaskNum = visitTask.VisitTaskNum,
                DigitPlaces = criterionInfo.DigitPlaces ?? 2,
            };

            return readingData;
        }


        /// <summary>
        /// 添加转化任务病灶信息
        /// </summary>
        /// <param name="visitTaskId"></param>
        /// <param name="beforeConvertedTaskId"></param>
        /// <returns></returns>
        public async Task AddConvertedTaskFocus(Guid visitTaskId, Guid beforeConvertedTaskId)
        {
            var originalTask = await _visitTaskRepository.Where(x => x.Id == visitTaskId).Include(x => x.TrialReadingCriterion).FirstNotNullAsync();

            var taskAnswer = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == beforeConvertedTaskId && x.ReadingQuestionTrial.QuestionType != QuestionType.AdjustReason && x.ReadingQuestionTrial.Type != "calculation").IgnoreAutoIncludes().AsNoTracking().ToListAsync();

            taskAnswer.ForEach(x =>
            {

                x.VisitTaskId = visitTaskId;

                x.Id = NewId.NextGuid();
            });


            var tableRowAnswers = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == beforeConvertedTaskId).AsNoTracking().ProjectTo<CopyTableAnswerRowInfo>(_mapper.ConfigurationProvider).IgnoreAutoIncludes().ToListAsync();

            tableRowAnswers.ForEach(x =>
            {
                x.VisitTaskId = visitTaskId;
                x.IsCurrentTaskAdd = false;
                x.FristAddTaskId = x.FristAddTaskId == beforeConvertedTaskId ? visitTaskId : x.FristAddTaskId;
                x.Id = NewId.NextGuid();
            });

            tableRowAnswers.ForEach(x =>
            {
                x.SplitRowId = tableRowAnswers.Where(y => y.OriginalId == x.SplitRowId).Select(y => y.Id).FirstOrDefault();
                x.MergeRowId = tableRowAnswers.Where(y => y.OriginalId == x.MergeRowId).Select(y => y.Id).FirstOrDefault();

            });

            var tableAnswer = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == beforeConvertedTaskId).IgnoreAutoIncludes().AsNoTracking().ToListAsync();

            tableAnswer.ForEach(x =>
            {
                x.Id = NewId.NextGuid();
                x.VisitTaskId = visitTaskId;
                x.RowId = tableRowAnswers.Where(y => y.OriginalId == x.RowId).Select(x => x.Id).FirstOrDefault();
            });
            var addrowInfo = _mapper.Map<List<ReadingTableAnswerRowInfo>>(tableRowAnswers);
            switch (originalTask.TrialReadingCriterion.CriterionType)
            {
                case CriterionType.IRECIST1Point1:
                    //非靶病灶全部数据复制,不可更改。支持如果状态为:显著增大需要自动改为: 显著增大(iUPD)
                    var stateQuestionId = await _readingTableQuestionTrialRepository.Where(x => x.TrialCriterionId == originalTask.TrialReadingCriterionId
                    && x.ReadingQuestionTrial.LesionType == LesionType.NonTargetLesions && x.QuestionMark == QuestionMark.State).Select(x => x.Id).FirstOrDefaultAsync();

                    tableAnswer.ForEach(x =>
                    {
                        if (x.TableQuestionId == stateQuestionId && x.Answer.EqEnum(NoTargetState.Increase))
                        {
                            x.Answer = NoTargetState.IUPD.GetEnumInt();
                        }
                    });

                    // 新转换为其它既往新病灶: 状态为消失、疑似、无法评估的新病灶自动转换为:其它既往新病灶,且不可以编辑

                    // 找到新病灶问题
                    var newLesionQuestion = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == originalTask.TrialReadingCriterionId && x.LesionType == LesionType.NewLesions).FirstOrDefaultAsync();


                    // 找到其他既往新病灶
                    var otherLesionQuestion = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == originalTask.TrialReadingCriterionId && x.LesionType == LesionType.OtherPreviousNewLesion).FirstOrDefaultAsync();



                    if (newLesionQuestion != null && otherLesionQuestion != null)
                    {
                        // 找到表格问题
                        var newLesionTableQuestionList = await _readingTableQuestionTrialRepository.Where(x => x.ReadingQuestionId == newLesionQuestion.Id).ToListAsync();

                        // 找到表格问题
                        var otherLesionTableQuestionList = await _readingTableQuestionTrialRepository.Where(x => x.ReadingQuestionId == otherLesionQuestion.Id).ToListAsync();

                        // 找到病灶状态
                        var newstateQuestionId = newLesionTableQuestionList.Where(x => x.QuestionMark == QuestionMark.State).Select(x => x.Id).FirstOrDefault();


                        var stateAnswers = new List<string>() {
                            NewLesionState.Loss.GetEnumInt(),
                            NewLesionState.Suspected.GetEnumInt(),
                            NewLesionState.UnableEvaluate.GetEnumInt()
                        };

                        var needRowIds = tableAnswer.Where(x => x.TableQuestionId == newstateQuestionId && stateAnswers.Contains(x.Answer)).Select(x => x.RowId).Distinct().ToList();



                        var index = 0;

                        addrowInfo.ForEach(x =>
                        {

                            if (needRowIds.Contains(x.Id))
                            {
                                index++;
                                x.RowIndex = index;
                                x.RowMark = otherLesionQuestion.OrderMark + x.RowIndex.GetLesionMark();
                                var fristAddTaskId = x.FristAddTaskId.Clone();
                                x.FromMark = fristAddTaskId == beforeConvertedTaskId ? string.Empty : x.RowMark;
                                x.FristAddTaskId = fristAddTaskId == beforeConvertedTaskId ? visitTaskId : fristAddTaskId;
                                x.QuestionId = otherLesionQuestion.Id;
                                x.OrderMark = otherLesionQuestion.OrderMark;
                                x.ReportMark = x.RowMark;

                            }


                        });


                        tableAnswer.ForEach(x =>
                        {
                            if (needRowIds.Contains(x.RowId))
                            {

                                var row = addrowInfo.Where(y => y.Id == x.RowId).FirstOrDefault();
                                if (row != null)
                                {
                                    x.RowIndex = row.RowIndex;
                                }


                                x.QuestionId = otherLesionQuestion.Id;

                                var newLesionTableQuestion = newLesionTableQuestionList.Where(y => y.Id == x.TableQuestionId).FirstOrDefault();
                                if (newLesionTableQuestion != null)
                                {
                                    x.TableQuestionId = otherLesionTableQuestionList.Where(y => y.QuestionMark == newLesionTableQuestion.QuestionMark).Select(x => x.Id).FirstOrDefault();

                                }

                            }

                        });
                    }

                    break;
            }
            await _readingTaskQuestionAnswerRepository.AddRangeAsync(taskAnswer);
            await _readingTableAnswerRowInfoRepository.AddRangeAsync(addrowInfo);
            await _readingTableQuestionAnswerRepository.AddRangeAsync(tableAnswer);
            await _readingTableQuestionAnswerRepository.SaveChangesAsync();
        }

        /// <summary>
        /// 获取阅片报告任务List
        /// </summary>
        /// <param name="visitTaskId"></param>
        /// <returns></returns>
        public async Task<List<VisitTaskInfo>> GetReadingReportTaskList(Guid visitTaskId)
        {
            var visitTaskInfo = await _visitTaskRepository.Where(x => x.Id == visitTaskId).Include(x => x.TrialReadingCriterion).FirstNotNullAsync();

            var isAdditionalQuestionId = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == visitTaskInfo.TrialReadingCriterionId && x.IsAdditional).IgnoreQueryFilters().Select(x => x.Id).ToListAsync();

            var taskquery = _visitTaskRepository
              .Where(x => (x.SubjectId == visitTaskInfo.SubjectId
              && (x.TaskState == TaskState.Effect || x.TaskState == TaskState.Freeze)
               && x.IsAnalysisCreate == visitTaskInfo.IsAnalysisCreate
              && x.DoctorUserId == visitTaskInfo.DoctorUserId
              && x.IsSelfAnalysis == visitTaskInfo.IsSelfAnalysis
             && x.VisitTaskNum <= visitTaskInfo.VisitTaskNum
              && x.ArmEnum == visitTaskInfo.ArmEnum
              && x.TrialReadingCriterionId == visitTaskInfo.TrialReadingCriterionId
              && x.ReadingCategory == ReadingCategory.Visit && x.ReadingTaskState == ReadingTaskState.HaveSigned) || x.Id == visitTaskId
            );
            if (visitTaskInfo.ReadingTaskState == ReadingTaskState.HaveSigned)
            {
                taskquery = _visitTaskRepository.Where(x => visitTaskInfo.ReportRelatedTaskIdList.Contains(x.Id) || x.Id == visitTaskInfo.Id);
            }
            if (visitTaskInfo.TrialReadingCriterion.IsReadingTaskViewInOrder != ReadingOrder.InOrder)
            {
                taskquery = _visitTaskRepository.Where(x => x.Id == visitTaskInfo.Id);
            }



            var taskInfoList = await taskquery.OrderBy(x => x.VisitTaskNum).Select(x => new VisitTaskInfo()
            {
                BlindName = x.TaskBlindName,
                IsBaseLine = x.SourceSubjectVisit.IsBaseLine,
                VisitTaskId = x.Id,
                TaskState = x.TaskState,
                TaskName = x.TaskName,
                LatestScanDate = x.SourceSubjectVisit != null ? x.SourceSubjectVisit.LatestScanDate : null,
                VisitTaskNum = x.VisitTaskNum,
                IsConvertedTask = x.IsConvertedTask,
                BeforeConvertedTaskId = x.BeforeConvertedTaskId,
                //CrterionDictionaryGroup = x.CrterionDictionaryGroup,
                IsCurrentTask = x.Id == visitTaskId,

            }).OrderBy(x => x.VisitTaskNum).ThenByDescending(x => x.TaskState).ToListAsync();


            taskInfoList.ForEach(x =>
            {
                x.CrterionDictionaryGroup = ReadingCommon.GetCrterionDictionaryGroup(x.IsConvertedTask);
            });

            var taskIds = taskInfoList.Select(x => x.VisitTaskId).ToList();

            var isHaveAdditionalTaskIds = await _readingTaskQuestionAnswerRepository.Where(x => taskIds.Contains(x.VisitTaskId) && isAdditionalQuestionId.Contains(x.ReadingQuestionTrialId)).Select(x => x.VisitTaskId).Distinct().ToListAsync();

            taskInfoList.ForEach(x =>
            {
                x.IsHaveAdditionalQuestion = isHaveAdditionalTaskIds.Contains(x.VisitTaskId);
            });
            return taskInfoList;
        }
    }
}