using DocumentFormat.OpenXml.EMMA;
using IRaCIS.Core.Application.Service.Reading.Dto;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infra.EFCore.Common;
using IRaCIS.Core.Infrastructure;
using MassTransit;
using Microsoft.AspNetCore.Mvc;
using System.Linq;

namespace IRaCIS.Core.Application.Service.ReadingCalculate
{
    [ApiExplorerSettings(GroupName = "Reading")]
    public class MRIPDFFAdvanceCalculateService(IRepository<ReadingTableQuestionAnswer> _readingTableQuestionAnswerRepository,
        IRepository<VisitTask> _visitTaskRepository,
        IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
        IRepository<ReadingTableQuestionTrial> _readingTableQuestionTrialRepository,
        IRepository<ReadingTableAnswerRowInfo> _readingTableAnswerRowInfoRepository,
        IRepository<ReadingGlobalTaskInfo> _readingGlobalTaskInfoRepository,
        IRepository<ReadingQuestionTrial> _readingQuestionTrialRepository,
        IRepository<SubjectVisit> _subjectVisitRepository,
        IRepository<OrganInfo> _organInfoRepository,
          IRepository<Dictionary> _dictionaryRepository,
             IRepository<ReadingTaskQuestionMark> _readingTaskQuestionMarkRepository,
        IRepository<DicomStudy> _dicomStudyRepository,
        IRepository<NoneDicomStudy> _noneDicomStudyRepository,
        IRepository<TumorAssessment_RECIST1Point1> _tumorAssessmentRepository,
        IGeneralCalculateService _generalCalculateService,
        IRepository<ReadingTaskQuestionAnswer> _readingTaskQuestionAnswerRepository, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, ICriterionCalculateService
    {


        private List<SiteVisitForTumor> siteVisitForTumorList = new List<SiteVisitForTumor>();

        /// <summary>
        /// 阅片导入
        /// </summary>
        /// <returns></returns>
        public async Task ReadingImport()
        {
        }


        /// <summary>
        /// 获取阅片的计算数据
        /// </summary>
        /// <param name="inDto"></param>
        /// <returns></returns>
        public async Task<object> GetReadingCalculationData(GetReadingCalculationDataInDto inDto)
        {
            return new
            {
            };
        }

        #region 删除病灶获取起始病灶序号
        /// <summary>
        /// 删除病灶获取起始病灶序号
        /// </summary>
        /// <returns></returns>
        public async Task<int> GetDeleteLesionStatrIndex(DeleteReadingRowAnswerInDto inDto)
        {
            return 1;


        }
        #endregion

        #region 获取阅片报告
        /// <summary>
        /// 获取阅片报告
        /// </summary>
        /// <param name="indto"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<GetReadingReportEvaluationOutDto> GetReadingReportEvaluation(GetReadingReportEvaluationInDto indto)
        {
            GetReadingReportEvaluationOutDto result = new GetReadingReportEvaluationOutDto();

            result.CalculateResult = await this.GetReportVerify(new GetReportVerifyInDto()
            {
                VisitTaskId = indto.VisitTaskId
            });

            var visitTaskInfo = await _visitTaskRepository.Where(x => x.Id == indto.VisitTaskId).FirstNotNullAsync();


            result.ReadingTaskState = visitTaskInfo.ReadingTaskState;
            var taskInfoList = await _generalCalculateService.GetReadingReportTaskList(indto.VisitTaskId);

            result.VisitTaskList = taskInfoList;

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

            var criterionId = visitTaskInfo.TrialReadingCriterionId;
            var questionList = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == criterionId && x.ShowQuestion != ShowQuestion.Hide).ToListAsync();
            var tableQuestionList = await _readingTableQuestionTrialRepository.Where(x => x.TrialCriterionId == criterionId).OrderBy(x => x.ShowOrder).ToListAsync();

            var lesionsIndexs = await _readingTableAnswerRowInfoRepository.Where(x => visitTaskIds.Contains(x.VisitTaskId)).GroupBy(x => new { x.QuestionId }).Select(x => new lesionsIndexDto()
            {
                QuestionId = x.Key.QuestionId,
                Rowindexs = x.Select(x => x.RowIndex).Distinct().OrderBy(x => x).ToList()

            }).ToListAsync();

            var tableAnsweRowInfos = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == indto.VisitTaskId).ProjectTo<TableAnsweRowInfo>(_mapper.ConfigurationProvider).ToListAsync();

            var answers = await _readingTaskQuestionAnswerRepository.Where(x => visitTaskIds.Contains(x.VisitTaskId)).ToListAsync();
            var tableAnswers = await _readingTableQuestionAnswerRepository.Where(x => visitTaskIds.Contains(x.VisitTaskId)).ToListAsync();
            var globalanswerList = await _readingGlobalTaskInfoRepository.Where(x => visitTaskIds.Contains(x.TaskId) && x.GlobalVisitTask.TaskState == TaskState.Effect && x.Answer != string.Empty).Select(x => new Globalanswer()
            {
                TaskId = x.TaskId,
                VisitTaskNum = x.GlobalVisitTask.VisitTaskNum,
                QuestionId = x.QuestionId,
                Answer = x.Answer
            }).ToListAsync();
            var alltableAnsweRowInfos = await _readingTableAnswerRowInfoRepository.Where(x => visitTaskIds.Contains(x.VisitTaskId)).ToListAsync();
            var organIds = alltableAnsweRowInfos.Where(x => x.OrganInfoId != null).Select(x => x.OrganInfoId).Distinct().ToList();
            var organInfos = await _organInfoRepository.Where(x => organIds.Contains(x.Id)).ToListAsync();

            var needChangeType = new List<QuestionMark?>() {
                QuestionMark.Organ,
                QuestionMark.Location,
                QuestionMark.Part,
            };

            // 第一级

            List<ReadingReportDto> questions = await _generalCalculateService.GetReadingReportQuestion
        (
         questionList,
         taskInfoList,
        globalanswerList,
         answers,
         tableAnsweRowInfos,
          tableQuestionList,
          alltableAnsweRowInfos,
          tableAnswers,
         organInfos,
          needChangeType
        );



            result.TaskQuestions = questions;



            return result;


        }
        #endregion

        /// <summary>
        /// 将上一次的访视病灶添加到这一次
        /// </summary>
        /// <param name="inDto"></param>
        /// <returns></returns>
        public async Task<AddTaskLesionAnswerFromLastTaskOutDto> AddTaskLesionAnswerFromLastTask(AddTaskLesionAnswerFromLastTaskInDto inDto)
        {
            var visitTaskId = inDto.VisitTaskId;
            var taskinfo = await _visitTaskRepository.Where(x => x.Id == visitTaskId).FirstNotNullAsync();
            var isReadingTaskViewInOrder = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == taskinfo.TrialReadingCriterionId).Select(x => x.IsReadingTaskViewInOrder).FirstOrDefaultAsync();
            var baseLineVisitId = await _subjectVisitRepository.Where(x => x.SubjectId == taskinfo.SubjectId && x.IsBaseLine).Select(x => x.Id).FirstOrDefaultAsync();

            if (!(await _readingTableQuestionAnswerRepository.AnyAsync(x => x.VisitTaskId == visitTaskId)))
            {
            


                var dictionList = await _dictionaryRepository.Where(x => x.Parent.Code == "Liver4Segmentation").OrderBy(x => x.ShowOrder).ToListAsync();


                var tableQuestion = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == taskinfo.TrialReadingCriterionId && x.LesionType == LesionType.FatFraction).FirstNotNullAsync();

                var tableQuestionList = await _readingTableQuestionTrialRepository.Where(x => x.ReadingQuestionId == tableQuestion.Id).ToListAsync();
                var LastVisitTaskId = await _visitTaskRepository.Where(x => x.ReadingCategory == ReadingCategory.Visit &&
                      x.TrialReadingCriterionId == taskinfo.TrialReadingCriterionId &&
                      x.IsAnalysisCreate == taskinfo.IsAnalysisCreate &&
                       x.DoctorUserId == taskinfo.DoctorUserId &&
                       x.IsSelfAnalysis == taskinfo.IsSelfAnalysis &&
                      x.SubjectId == taskinfo.SubjectId && x.ReadingTaskState == ReadingTaskState.HaveSigned && x.VisitTaskNum < taskinfo.VisitTaskNum && x.TaskState == TaskState.Effect && x.ArmEnum == taskinfo.ArmEnum
                      ).OrderByDescending(x => x.VisitTaskNum).Select(x => x.Id).FirstOrDefaultAsync();


                List<TableMarkInfo> marks = await _readingTaskQuestionMarkRepository.Where(x => x.VisitTaskId == LastVisitTaskId && x.RowId != null).ProjectTo<TableMarkInfo>(_mapper.ConfigurationProvider).ToListAsync();


                marks.ForEach(x => {

                    x.VisitTaskId = visitTaskId;
                });

                List<ReadingTableAnswerRowInfo> rowlist = new List<ReadingTableAnswerRowInfo>();
                List<ReadingTableQuestionAnswer> tableAnswerList = new List<ReadingTableQuestionAnswer>();

                decimal num = 1;
                foreach (var item in dictionList)
                {
                    var guid = NewId.NextGuid();
                    marks.ForEach(x => {
                        x.RowId = x.RowIndex == num ? guid : x.RowId;
                    });
                    rowlist.Add(new ReadingTableAnswerRowInfo()
                    {
                        FristAddTaskId = visitTaskId,
                        IsCurrentTaskAdd = true,
                        BlindName = taskinfo.TaskBlindName,
                        OrderMark = tableQuestion.OrderMark,
                        VisitTaskId = visitTaskId,
                        TrialId = taskinfo.TrialId,
                        QuestionId = tableQuestion.Id,
                        RowIndex = num,
                        Id = guid,
                    });

                    tableAnswerList.Add(new ReadingTableQuestionAnswer()
                    {
                        QuestionId = tableQuestion.Id,
                        Answer = item.Code,
                        TableQuestionId = tableQuestionList.Where(x => x.QuestionMark == QuestionMark.liverSegmentation).Select(x => x.Id).FirstOrDefault(),
                        VisitTaskId = visitTaskId,
                        TrialId = taskinfo.TrialId,
                        RowIndex = num,
                        RowId = guid,
                    });

                    foreach (var otherQuestion in tableQuestionList.Where(x => !tableAnswerList.Any(y => y.RowId == guid && y.TableQuestionId == x.Id)))
                    {
                        tableAnswerList.Add(new ReadingTableQuestionAnswer()
                        {
                            Answer = otherQuestion.DefaultValue,
                            QuestionId = tableQuestion.Id,
                            TrialId = taskinfo.TrialId,
                            VisitTaskId = taskinfo.Id,
                            RowId = guid,
                            RowIndex = num,
                            TableQuestionId = otherQuestion.Id,
                        });
                    }


                    num++;
                }
                await _readingTableAnswerRowInfoRepository.AddRangeAsync(rowlist);
                await _readingTableQuestionAnswerRepository.AddRangeAsync(tableAnswerList);

                await _readingTaskQuestionMarkRepository.AddRangeAsync(_mapper.Map<List<ReadingTaskQuestionMark>>(marks));
                await _readingTableQuestionAnswerRepository.SaveChangesAsync();
            }
               

            return new AddTaskLesionAnswerFromLastTaskOutDto()
            {
                IsBaseLine = taskinfo.SourceSubjectVisitId == baseLineVisitId,
            };

        }

        /// <summary>
        /// 测试计算
        /// </summary>
        /// <param name="visitTaskId"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task TestCalculate(Guid visitTaskId, QuestionType type)
        {
            ReadingCalculateDto readingData = await _generalCalculateService.GetReadingCalculateDto(visitTaskId);
            await ReadingCalculate(readingData, new List<QuestionType>() { type });
        }

        /// <summary>
        /// 计算任务
        /// </summary>
        /// <param name="inDto"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task CalculateTask(CalculateTaskInDto inDto)
        {
            ReadingCalculateDto readingData = await _generalCalculateService.GetReadingCalculateDto(inDto.VisitTaskId);
            readingData.IsChangeOtherTask = inDto.IsChangeOtherTask;
            await ReadingCalculate(readingData);
        }




        /// <summary>
        /// 自动计算
        /// </summary>
        /// <param name="inDto"></param>
        /// <param name="calculateType"></param>
        /// <returns></returns>
        public async Task ReadingCalculate(ReadingCalculateDto inDto, List<QuestionType>? calculateType = null)
        {

            //await this.CalculateAvg(inDto);
            inDto = await _generalCalculateService.GetReadingCalculateDto(inDto.VisitTaskId);
            var needAddList = new List<ReadingTaskQuestionAnswer>();
            List<ReadingCalculateData> calculateList = new List<ReadingCalculateData>()
            {
				// 脂肪平均
				new ReadingCalculateData (){QuestionType=QuestionType.TotalMeanFraction,GetStringFun=GetFatFractionAvg},

                // 脂肪分级
				new ReadingCalculateData (){QuestionType=QuestionType.FattyLiverGrading,GetStringFun=GetFattyLiverGrading},
            };


            if (calculateType != null)
            {
                calculateList = calculateList.Where(x => calculateType.Contains(x.QuestionType)).ToList();
            }



            foreach (var calculate in calculateList)
            {
                var item = inDto.QuestionInfo.FirstOrDefault(x => x.QuestionType == calculate.QuestionType);

                if (item != null)
                {
                    //计算答案  


                    #region 计算答案
                    if (calculate.GetDecimalFun != null)
                    {
                        item.Answer = (await calculate.GetDecimalFun(inDto)).ToString();

                    }
                    else if (calculate.GetDecimalNullFun != null)
                    {
                        var value = await calculate.GetDecimalNullFun(inDto);
                        item.Answer = value == null ? "NA" : value.Value.ToString();
                    }
                    else if (calculate.GetStringFun != null)
                    {
                        item.Answer = await calculate.GetStringFun(inDto);
                    }
                    #endregion
                    // 修改修约小数位数

                    List<ValueOfType?> valueOfTypes = new List<ValueOfType?>() {

                               ValueOfType.Decimals,
                               ValueOfType.Percentage
                            };

                    if (inDto.DigitPlaces != -1 && calculate.GetDecimalFun != null && calculate.GetDecimalNullFun != null)
                    {
                        try
                        {

                            if (valueOfTypes.Contains(item.ValueType))
                            {
                                item.Answer = decimal.Round(decimal.Parse(item.Answer ?? "0"), inDto.DigitPlaces, MidpointRounding.AwayFromZero).ToString("F" + inDto.DigitPlaces.ToString());
                            }
                        }
                        catch (Exception)
                        {

                        }
                    }

                    needAddList.Add(new ReadingTaskQuestionAnswer()
                    {
                        Answer = item.Answer,
                        ReadingQuestionTrialId = item.QuestionId,
                    });
                }
            }



            var questionIds = needAddList.Select(x => x.ReadingQuestionTrialId).ToList();

            await _readingTaskQuestionAnswerRepository.BatchDeleteNoTrackingAsync(x => questionIds.Contains(x.ReadingQuestionTrialId) && x.VisitTaskId == inDto.VisitTaskId);
            needAddList.ForEach(x =>
            {
                x.SubjectId = inDto.SubjectId;
                x.ReadingQuestionCriterionTrialId = inDto.CriterionId;
                x.VisitTaskId = inDto.VisitTaskId;
                x.TrialId = inDto.TrialId;
                x.SubjectId = inDto.SubjectId;
            });

            await _readingTaskQuestionAnswerRepository.AddRangeAsync(needAddList);

            await _readingTaskQuestionAnswerRepository.SaveChangesAsync();

        }

        /// <summary>
        /// 获取脂肪分数平均值
        /// </summary>
        /// <param name="inDto"></param>
        /// <returns></returns>
        public async Task<string> GetFatFractionAvg(ReadingCalculateDto inDto)
        {
            decimal result = 0;

            var rowInfo = inDto.QuestionInfo.Where(x => x.LesionType == LesionType.FatFraction)
                .SelectMany(x => x.TableRowInfoList).ToList();

            var tableQuestionList = rowInfo.Where(x=>x.TableQuestionList.Any(x=>x.QuestionMark== QuestionMark.IsMeasurable && x.Answer.EqEnum(YesOrNoOrNa.Yes))).SelectMany(x => x.TableQuestionList).ToList();

            if (rowInfo.Any(x => x.TableQuestionList.Any(x => x.QuestionMark == QuestionMark.MRIPDFF && x.Answer.IsNullOrEmpty())))
            {
                return string.Empty;
            }
            if (tableQuestionList.Count() == 0)
            {
                return "NE";
            }
            result = tableQuestionList.Where(x => x.QuestionMark == QuestionMark.MRIPDFF).Average(x => x.Answer.IsNullOrEmptyReturn0());
            return decimal.Round(result, inDto.DigitPlaces, MidpointRounding.AwayFromZero).ToString("F" + inDto.DigitPlaces.ToString()); ;

        }

        /// <summary>
        /// 获取脂肪肝分级
        /// </summary>
        /// <param name="inDto"></param>
        /// <returns></returns>
        public async Task<string> GetFattyLiverGrading(ReadingCalculateDto inDto)
        {
            var answer = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.TotalMeanFraction).Select(x => x.Answer).FirstIsNullReturnEmpty();
            if (answer == "NE")
            {
                return FattyLiverClassification.NE.GetEnumInt();
            }
            else if(answer == string.Empty) 
            {
                return string.Empty;
            }

            if (decimal.TryParse(answer, out var value))
            {
                return value switch
                {
                    < 5 => FattyLiverClassification.Level0.GetEnumInt(),
                    < 10 => FattyLiverClassification.Level1.GetEnumInt(),
                    < 25 => FattyLiverClassification.Level2.GetEnumInt(),
                    _ => FattyLiverClassification.Level3.GetEnumInt()
                };
            }

            return FattyLiverClassification.NE.GetEnumInt();
        }

        /// <summary>
        /// 计算平均值
        /// </summary>
        /// <returns></returns>
        //public async Task CalculateAvg(ReadingCalculateDto inDto)
        //{
        //    // 脂肪分数的表格问题Id
        //    var questionInfo = inDto.QuestionInfo.Where(x => x.LesionType == LesionType.FatFraction).FirstOrDefault();

        //    List<ReadingTableQuestionAnswer> tableAnswers = new List<ReadingTableQuestionAnswer>();


        //    foreach (var item in questionInfo.TableRowInfoList)
        //    {
        //        var avg = item.TableQuestionList.Where(x => x.QuestionMark == QuestionMark.AverageValue).FirstOrDefault();
        //        var avgAnswer = string.Empty;
        //        List<QuestionMark?> questionMarks = new List<QuestionMark?>()
        //        {
        //            QuestionMark.FirstMeasurement,
        //            QuestionMark.SecondMeasurement,
        //            QuestionMark.ThirdMeasurement,
        //            QuestionMark.FourthMeasurement,
        //        };
        //        var answers = item.TableQuestionList.Where(x => questionMarks.Contains(x.QuestionMark)).Select(x=>x.Answer).ToList();
        //        if (answers.Count() == 4 && !answers.Any(x => x.IsNullOrEmpty()))
        //        {
        //           var  avgAnswernum= answers.Select(x=>x.IsNullOrEmptyReturn0()).Average(x=>x);
        //           avgAnswer = decimal.Round(avgAnswernum, inDto.DigitPlaces, MidpointRounding.AwayFromZero).ToString("F" + inDto.DigitPlaces.ToString());
        //        }
        //        if(item.TableQuestionList.Where(x => x.QuestionMark== QuestionMark.IsMeasurable).Select(x => x.Answer).FirstOrDefault().EqEnum(YesOrNoOrNa.No))
        //        {
        //            avgAnswer = "NE";
        //        }
        //        tableAnswers.Add(new ReadingTableQuestionAnswer()
        //        {
        //            Answer = avgAnswer,
        //            VisitTaskId = inDto.VisitTaskId,
        //            QuestionId = avg.QuestionId,
        //            TableQuestionId = avg.TableQuestionId,
        //            TrialId = inDto.TrialId,
        //            RowIndex = avg.RowIndex,
        //            RowId = avg.RowId,

        //        });

        //        await _readingTableQuestionAnswerRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId && x.RowId == item.RowId && x.TableQuestionId == avg.TableQuestionId);
        //    }

        //    await _readingTableQuestionAnswerRepository.AddRangeAsync(tableAnswers);
        //    await _readingTableQuestionAnswerRepository.SaveChangesAsync();

        //}



        public async Task<GetReportVerifyOutDto> GetReportVerify(GetReportVerifyInDto inDto)
        {
            return new GetReportVerifyOutDto()
            {

            };
        }

        public async Task VerifyVisitTaskQuestions(VerifyVisitTaskQuestionsInDto inDto)
        {
            ReadingCalculateDto readingData = await _generalCalculateService.GetReadingCalculateDto(inDto.VisitTaskId);

            var markList = await _readingTaskQuestionMarkRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId).ToListAsync();
            var rowInfo = readingData.QuestionInfo.Where(x => x.LesionType == LesionType.FatFraction)
              .SelectMany(x => x.TableRowInfoList).ToList();

            var tableQuestionList = rowInfo.Where(x => x.TableQuestionList.Any(x => x.QuestionMark == QuestionMark.MRIPDFF && x.Answer.IsNotNullOrEmpty())).ToList();

            if (tableQuestionList.Count() != 4)
            {
                throw new BusinessValidationFailedException(_localizer["MRIPDFF_AllNeedToBeMark"]);
            }

            var instanceCount = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.InstanceId != null).Select(x => x.InstanceId).Distinct().CountAsync();

            if (instanceCount > 1)
            {
                throw new BusinessValidationFailedException(_localizer["MRIPDFFAdvance_MarkMustBeSameInstance"]);
            }

            //try
            //{
            //    List<QuestionMark?> questionMarkList = new List<QuestionMark?>() { QuestionMark.FirstMeasurement, QuestionMark.SecondMeasurement, QuestionMark.ThirdMeasurement, QuestionMark.FourthMeasurement };
            //    var measuredValueList = rowInfo.SelectMany(x => x.TableQuestionList).Where(x =>x.Answer.IsNotNullOrEmpty()&& questionMarkList.Contains(x.QuestionMark)).Select(x => decimal.Parse(x.Answer)).ToList();
            //    if (measuredValueList.Any(x => x > 100))
            //    {
            //        throw new BusinessValidationFailedException(_localizer["MRIPDFF_MeasurementGT100"]);
            //    }
            //}
            //catch (Exception)
            //{

            //    throw new BusinessValidationFailedException(_localizer["MRIPDFF_MeasurementGT100"]);
            //}

            //var notableQuestionList = rowInfo.Where(x => x.TableQuestionList.Any(x => x.QuestionMark == QuestionMark.IsMeasurable && x.Answer.EqEnum(YesOrNoOrNa.No))).ToList();


            //foreach (var item in notableQuestionList)
            //{
            //    if (markList.Any(x => x.RowId == item.RowId && x.MeasureData.IsNotNullOrEmpty()))
            //    {
            //        throw new BusinessValidationFailedException(_localizer["MRIPDFF_NeedClearMark"]);
            //    }
            //}

        }
    }
}
