using IRaCIS.Core.Domain.Share;
using System.Text;
using Microsoft.AspNetCore.Hosting;
using IRaCIS.Core.Infrastructure;
using Medallion.Threading;
using FellowOakDicom;
using FellowOakDicom.Imaging.Codec;
using System.Data;
using IRaCIS.Core.Domain.Models;
using FellowOakDicom.Network;
using IRaCIS.Core.SCP.Service;
using IRaCIS.Core.Infra.EFCore;
using MassTransit;
using System.Runtime.Intrinsics.X86;
using Serilog.Sinks.File;

namespace IRaCIS.Core.SCP.Service
{
    public class DicomArchiveService : BaseService, IDicomArchiveService
    {
        private readonly IRepository<SCPPatient> _patientRepository;
        private readonly IRepository<SCPStudy> _studyRepository;
        private readonly IRepository<SCPSeries> _seriesRepository;
        private readonly IRepository<SCPInstance> _instanceRepository;
        private readonly IRepository<Dictionary> _dictionaryRepository;
        private readonly IDistributedLockProvider _distributedLockProvider;


        private List<Guid> _instanceIdList = new List<Guid>();

        public DicomArchiveService(IRepository<SCPPatient> patientRepository, IRepository<SCPStudy> studyRepository,
            IRepository<SCPSeries> seriesRepository,
            IRepository<SCPInstance> instanceRepository,
            IRepository<Dictionary> dictionaryRepository,
            IDistributedLockProvider distributedLockProvider)
        {
            _distributedLockProvider = distributedLockProvider;
            _studyRepository = studyRepository;
            _patientRepository = patientRepository;
            _seriesRepository = seriesRepository;
            _instanceRepository = instanceRepository;
            _dictionaryRepository = dictionaryRepository;

        }




        /// <summary>
        /// 单个文件接收 归档
        /// </summary>
        /// <param name="dataset"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task<Guid> ArchiveDicomFileAsync(DicomDataset dataset, Guid trialId, Guid trialSiteId, string fileRelativePath, string callingAE, string calledAE,long fileSize)
        {
            string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID);
            string seriesInstanceUid = dataset.GetString(DicomTag.SeriesInstanceUID);
            string sopInstanceUid = dataset.GetString(DicomTag.SOPInstanceUID);

            string patientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID,string.Empty);

            //Guid patientId= IdentifierHelper.CreateGuid(patientIdStr);
            Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid,trialId.ToString());
            Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, trialId.ToString());
            Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid, trialId.ToString());

            var isStudyNeedAdd = false;
            var isSeriesNeedAdd = false;
            var isInstanceNeedAdd = false;
            var isPatientNeedAdd = false;

            //var @lock = _distributedLockProvider.CreateLock($"{studyInstanceUid}");

            //using (@lock.Acquire())
            {
                var findPatient = await _patientRepository.FirstOrDefaultAsync(t => t.PatientIdStr == patientIdStr && t.TrialSiteId==trialSiteId );
                var findStudy = await _studyRepository.FirstOrDefaultAsync(t=>t.Id== studyId);
                var findSerice = await _seriesRepository.FirstOrDefaultAsync(t => t.Id ==   seriesId);
                var findInstance = await _instanceRepository.FirstOrDefaultAsync(t => t.Id == instanceId);

                DateTime? studyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.StudyDate).Add(dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.StudyTime).TimeOfDay);

                //先传输了修改了患者编号的,又传输了没有修改患者编号的,导致后传输的没有修改患者编号的下面的检查为0
                if (findPatient == null && findStudy==null)
                {
                    isPatientNeedAdd = true;


                    findPatient = new SCPPatient()
                    {
                        Id = NewId.NextSequentialGuid(),
                        TrialId=trialId,
                        TrialSiteId=trialSiteId,
                        PatientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
                        PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
                        PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty),
                        PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty),
                        PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty),

                        EarliestStudyTime = studyTime,
                        LatestStudyTime = studyTime,
                        LatestPushTime = DateTime.Now,
                    };

                    if (findPatient.PatientBirthDate.Length == 8)
                    {
                        var birthDateStr = $"{findPatient.PatientBirthDate[0]}{findPatient.PatientBirthDate[1]}{findPatient.PatientBirthDate[2]}{findPatient.PatientBirthDate[3]}-{findPatient.PatientBirthDate[4]}{findPatient.PatientBirthDate[5]}-{findPatient.PatientBirthDate[6]}{findPatient.PatientBirthDate[7]}";

                        var yearStr = $"{findPatient.PatientBirthDate[0]}{findPatient.PatientBirthDate[1]}{findPatient.PatientBirthDate[2]}{findPatient.PatientBirthDate[3]}";

                        int year = 0;

                        var canParse = int.TryParse(yearStr, out year);

                        if (canParse && year > 1900)
                        {
                            findPatient.PatientBirthDate = birthDateStr;

                            DateTime birthDate;

                            if (findPatient.PatientAge == string.Empty && studyTime.HasValue && DateTime.TryParse(findPatient.PatientBirthDate,out birthDate))
                            {
                                var patientAge = studyTime.Value.Year - birthDate.Year;
                                // 如果生日还未到,年龄减去一岁
                                if (studyTime.Value < birthDate.AddYears(patientAge))
                                {
                                    patientAge--;
                                }

                                findPatient.PatientAge = patientAge.ToString();
                            }

                        }
                        else
                        {
                            findPatient.PatientBirthDate = string.Empty;
                        }

                    }
                }
                else
                {
                    if (studyTime < findPatient.EarliestStudyTime)
                    {
                        findPatient.EarliestStudyTime = studyTime;
                    }
                    if (studyTime > findPatient.LatestStudyTime)
                    {
                        findPatient.LatestStudyTime = studyTime;
                    }

                    findPatient.LatestPushTime = DateTime.Now;
                }

                if (findStudy == null)
                {
                    isStudyNeedAdd = true;
                    findStudy = new SCPStudy
                    {
                        CalledAE = calledAE,
                        CallingAE = callingAE,

                        PatientId = findPatient.Id,
                        Id = studyId,
                        TrialId = trialId,
                        TrialSiteId = trialSiteId,
                        StudyInstanceUid = studyInstanceUid,
                        StudyTime = studyTime,
                        Modalities = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
                        //ModalityForEdit = modalityForEdit,
                        Description = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),
                        InstitutionName = dataset.GetSingleValueOrDefault(DicomTag.InstitutionName, string.Empty),
                        PatientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
                        PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
                        PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty),
                        PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty),
                        BodyPartExamined = dataset.GetSingleValueOrDefault(DicomTag.BodyPartExamined, string.Empty),

                        StudyId = dataset.GetSingleValueOrDefault(DicomTag.StudyID, string.Empty),
                        AccessionNumber = dataset.GetSingleValueOrDefault(DicomTag.AccessionNumber, string.Empty),

                        //需要特殊处理
                        PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty),


                        AcquisitionTime = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionTime, string.Empty),
                        AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty),
                        TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty),



                        //IsDoubleReview = addtionalInfo.IsDoubleReview,
                        SeriesCount = 0,
                        InstanceCount = 0
                    };


                    if (findStudy.PatientBirthDate.Length == 8)
                    {
                        findStudy.PatientBirthDate = $"{findStudy.PatientBirthDate[0]}{findStudy.PatientBirthDate[1]}{findStudy.PatientBirthDate[2]}{findStudy.PatientBirthDate[3]}-{findStudy.PatientBirthDate[4]}{findStudy.PatientBirthDate[5]}-{findStudy.PatientBirthDate[6]}{findStudy.PatientBirthDate[7]}";
                    }
                }


                if (findSerice == null)
                {
                    isSeriesNeedAdd = true;

                    findSerice = new SCPSeries
                    {
                        Id = seriesId,
                        StudyId = findStudy.Id,

                        StudyInstanceUid = findStudy.StudyInstanceUid,
                        SeriesInstanceUid = seriesInstanceUid,
                        SeriesNumber = dataset.GetSingleValueOrDefault(DicomTag.SeriesNumber, 1),
                        //SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, DateTime.Now).TimeOfDay),
                        //SeriesTime = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.SeriesDate) + dataset.GetSingleValue<string>(DicomTag.SeriesTime), out DateTime dt) ? dt : null,
                        SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.SeriesDate).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.SeriesTime).TimeOfDay),
                        Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
                        Description = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),
                        SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),

                        ImagePositionPatient = dataset.GetSingleValueOrDefault(DicomTag.ImagePositionPatient, string.Empty),
                        ImageOrientationPatient = dataset.GetSingleValueOrDefault(DicomTag.ImageOrientationPatient, string.Empty),
                        BodyPartExamined = dataset.GetSingleValueOrDefault(DicomTag.BodyPartExamined, string.Empty),
                        SequenceName = dataset.GetSingleValueOrDefault(DicomTag.SequenceName, string.Empty),
                        ProtocolName = dataset.GetSingleValueOrDefault(DicomTag.ProtocolName, string.Empty),
                        ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),

                        AcquisitionTime = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionTime, string.Empty),
                        AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty),
                        TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty),


                        InstanceCount = 0
                    };

                    ++findStudy.SeriesCount;
                }


                if (findInstance == null)
                {
                    isInstanceNeedAdd = true;
                    findInstance = new SCPInstance
                    {
                        Id = instanceId,
                        StudyId = findStudy.Id,
                        SeriesId = findSerice.Id,
                        StudyInstanceUid = findStudy.StudyInstanceUid,
                        SeriesInstanceUid = findSerice.SeriesInstanceUid,

                        SopInstanceUid = sopInstanceUid,
                        InstanceNumber = dataset.GetSingleValueOrDefault(DicomTag.InstanceNumber, 1),
                        InstanceTime = dataset.GetSingleValueOrDefault(DicomTag.ContentDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.ContentDate).Add(dataset.GetSingleValueOrDefault(DicomTag.ContentTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.ContentTime).TimeOfDay),
                        //InstanceTime = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.ContentDate) + dataset.GetSingleValue<string>(DicomTag.ContentTime), out DateTime dt) ? dt : null,
                        //InstanceTime = dataset.GetSingleValueOrDefault(DicomTag.ContentDate,(DateTime?)null)?.Add(dataset.GetSingleValueOrDefault(DicomTag.ContentTime, TimeSpan.Zero)),
                        //dataset.GetSingleValueOrDefault(DicomTag.ContentDate,DateTime.Now);//, DicomTag.ContentTime)
                        CPIStatus = false,
                        ImageRows = dataset.GetSingleValueOrDefault(DicomTag.Rows, 0),
                        ImageColumns = dataset.GetSingleValueOrDefault(DicomTag.Columns, 0),
                        SliceLocation = dataset.GetSingleValueOrDefault(DicomTag.SliceLocation, 0),

                        SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
                        NumberOfFrames = dataset.GetSingleValueOrDefault(DicomTag.NumberOfFrames, 0),
                        PixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.PixelSpacing, string.Empty),
                        ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
                        FrameOfReferenceUID = dataset.GetSingleValueOrDefault(DicomTag.FrameOfReferenceUID, string.Empty),
                        WindowCenter = dataset.GetSingleValueOrDefault(DicomTag.WindowCenter, string.Empty),
                        WindowWidth = dataset.GetSingleValueOrDefault(DicomTag.WindowWidth, string.Empty),

                        Path = fileRelativePath,

                        FileSize= fileSize,

                    };

                    ++findStudy.InstanceCount;
                    ++findSerice.InstanceCount;
                }

                if (isPatientNeedAdd)
                {
                    var ss = await _patientRepository.AddAsync(findPatient);
                }
                if (isStudyNeedAdd)
                {
                    var dd = await _studyRepository.AddAsync(findStudy);
                }
                else
                {
                    await _studyRepository.BatchUpdateNoTrackingAsync(t => t.Id == findStudy.Id, t => new SCPStudy() { IsUploadFinished = false });
                }

                if (isSeriesNeedAdd)
                {
                    await _seriesRepository.AddAsync(findSerice);
                }
                if (isInstanceNeedAdd)
                {
                    await _instanceRepository.AddAsync(findInstance);
                }
                else
                {
                    await _instanceRepository.BatchUpdateNoTrackingAsync(t => t.Id == instanceId, u => new SCPInstance() { Path = fileRelativePath,FileSize=fileSize });
                }

                await _studyRepository.SaveChangesAsync();

                return findStudy.Id;
            }

        }


        // 从DICOM文件中获取使用的字符集
        private string GetEncodingVaulueFromDicomFile(DicomDataset dataset, DicomTag dicomTag)
        {

            // 获取DICOM文件的特定元素,通常用于指示使用的字符集
            var charset = dataset.GetSingleValueOrDefault(DicomTag.SpecificCharacterSet, string.Empty);

            var dicomEncoding = DicomEncoding.GetEncoding(charset);


            var dicomStringElement = dataset.GetDicomItem<DicomStringElement>(dicomTag);

            var bytes = dicomStringElement.Buffer.Data;


            return dicomEncoding.GetString(bytes);


            //// 从DICOM文件中获取使用的字符集
            //string filePath = "C:\\Users\\hang\\Documents\\WeChat Files\\wxid_r2imdzb7j3q922\\FileStorage\\File\\2024-05\\1.2.840.113619.2.80.169103990.5390.1271401378.4.dcm";
            //DicomFile dicomFile = DicomFile.Open(filePath);

            //// 获取DICOM文件的特定元素,通常用于指示使用的字符集
            //var charset = dicomFile.Dataset.GetSingleValueOrDefault(DicomTag.SpecificCharacterSet, string.Empty);

            //var dicomEncoding = DicomEncoding.GetEncoding(charset);

            //var value = dicomFile.Dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty);

            //var dicomStringElement = dicomFile.Dataset.GetDicomItem<DicomStringElement>(DicomTag.PatientName);

            //var bytes = dicomStringElement.Buffer.Data;

            //var aa= dicomEncoding.GetString(bytes);


        }
    }
}