using FellowOakDicom.Network;
using FellowOakDicom;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using IRaCIS.Core.SCP.Service;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Infra.EFCore;
using Medallion.Threading;
using IRaCIS.Core.Domain.Share;
using Serilog;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;
using Microsoft.Extensions.Options;
using System.Data;
using FellowOakDicom.Imaging;
using SharpCompress.Common;
using SixLabors.ImageSharp.Formats.Jpeg;
using IRaCIS.Core.Infrastructure;

namespace IRaCIS.Core.SCP.Service
{

    public class DicomSCPServiceOption
    {
        public List<string> CalledAEList { get; set; }

        public string ServerPort { get; set; }
    }




    public class CStoreSCPService : DicomService, IDicomServiceProvider, IDicomCStoreProvider, IDicomCEchoProvider
    {
        private IServiceProvider _serviceProvider { get; set; }

        private List<Guid> _SCPStudyIdList { get; set; } = new List<Guid>();

        private SCPImageUpload _upload { get; set; }

        private Guid _trialId { get; set; }

        private Guid _trialSiteId { get; set; }



        private static readonly DicomTransferSyntax[] _acceptedTransferSyntaxes = new DicomTransferSyntax[]
        {
               DicomTransferSyntax.ExplicitVRLittleEndian,
               DicomTransferSyntax.ExplicitVRBigEndian,
               DicomTransferSyntax.ImplicitVRLittleEndian
        };

        private static readonly DicomTransferSyntax[] _acceptedImageTransferSyntaxes = new DicomTransferSyntax[]
        {
                // Lossless
               DicomTransferSyntax.JPEGLSLossless,   //1.2.840.10008.1.2.4.80
               DicomTransferSyntax.JPEG2000Lossless, //1.2.840.10008.1.2.4.90
               DicomTransferSyntax.JPEGProcess14SV1, //1.2.840.10008.1.2.4.70
               DicomTransferSyntax.JPEGProcess14,    //1.2.840.10008.1.2.4.57 JPEG Lossless, Non-Hierarchical (Process 14)
               DicomTransferSyntax.RLELossless,      //1.2.840.10008.1.2.5
               // Lossy
               DicomTransferSyntax.JPEGLSNearLossless,//1.2.840.10008.1.2.4.81"
               DicomTransferSyntax.JPEG2000Lossy,     //1.2.840.10008.1.2.4.91
               DicomTransferSyntax.JPEGProcess1,      //1.2.840.10008.1.2.4.50
               DicomTransferSyntax.JPEGProcess2_4,    //1.2.840.10008.1.2.4.51
               // Uncompressed
               DicomTransferSyntax.ExplicitVRLittleEndian, //1.2.840.10008.1.2.1
               DicomTransferSyntax.ExplicitVRBigEndian,    //1.2.840.10008.1.2.2
               DicomTransferSyntax.ImplicitVRLittleEndian  //1.2.840.10008.1.2
        };


        public CStoreSCPService(INetworkStream stream, Encoding fallbackEncoding, Microsoft.Extensions.Logging.ILogger log, DicomServiceDependencies dependencies)
            : base(stream, fallbackEncoding, log, dependencies)
        {
        }




        public Task OnReceiveAssociationRequestAsync(DicomAssociation association)
        {

            _upload = new SCPImageUpload() { StartTime = DateTime.Now, CallingAE = association.CallingAE, CalledAE = association.CalledAE, CallingAEIP = association.RemoteHost };


            Log.Logger.Warning($"接收到来自{association.CallingAE}的连接");

            _serviceProvider = (IServiceProvider)this.UserState;



            var _trialDicomAERepository = _serviceProvider.GetService<IRepository<TrialDicomAE>>();


            var trialDicomAEList = _trialDicomAERepository.Select(t => new { t.CalledAE, t.TrialId }).ToList();
            var trialCalledAEList = trialDicomAEList.Select(t => t.CalledAE).ToList();

            Log.Logger.Information("当前系统配置:", string.Join('|', trialDicomAEList));

            var findCalledAE = trialDicomAEList.Where(t => t.CalledAE == association.CalledAE).FirstOrDefault();

            var isCanReceiveIamge = false;

            if (findCalledAE != null)
            {
                _trialId = findCalledAE.TrialId;

                var _trialSiteDicomAERepository = _serviceProvider.GetService<IRepository<TrialSiteDicomAE>>();


                var findTrialSiteAE = _trialSiteDicomAERepository.Where(t => t.CallingAE == association.CallingAE && t.TrialId==_trialId).FirstOrDefault();

                if (findTrialSiteAE != null)
                {
                    _trialSiteId = findTrialSiteAE.TrialSiteId;

                    isCanReceiveIamge = true;
                }

               
            }

            if (association.CallingAE == "test-callingAE")
            {
                isCanReceiveIamge = true;
            }

            if (!trialCalledAEList.Contains(association.CalledAE) || isCanReceiveIamge == false)
            {

                Log.Logger.Warning($"拒绝CallingAE:{association.CallingAE}  CalledAE:{association.CalledAE}的连接");

                return SendAssociationRejectAsync(
                    DicomRejectResult.Permanent,
                    DicomRejectSource.ServiceUser,
                    DicomRejectReason.CalledAENotRecognized);
            }

            foreach (var pc in association.PresentationContexts)
            {
                if (pc.AbstractSyntax == DicomUID.Verification)
                {
                    pc.AcceptTransferSyntaxes(_acceptedTransferSyntaxes);
                }
                else if (pc.AbstractSyntax.StorageCategory != DicomStorageCategory.None)
                {
                    pc.AcceptTransferSyntaxes(_acceptedImageTransferSyntaxes);
                }
            }



            return SendAssociationAcceptAsync(association);
        }


        public async Task OnReceiveAssociationReleaseRequestAsync()
        {
            await DataMaintenanceAsaync();

            //记录监控

            var _SCPImageUploadRepository = _serviceProvider.GetService<IRepository<SCPImageUpload>>();

            _upload.EndTime = DateTime.Now;
            _upload.StudyCount = _SCPStudyIdList.Count;
            _upload.TrialId = _trialId;
            _upload.TrialSiteId = _trialSiteId;

            await _SCPImageUploadRepository.AddAsync(_upload, true);

            await SendAssociationReleaseResponseAsync();
        }


        private async Task DataMaintenanceAsaync()
        {
            Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE}传输结束:开始维护数据,处理检查Modality");



            //处理检查Modality
            var _dictionaryRepository = _serviceProvider.GetService<IRepository<Dictionary>>();
            var _seriesRepository = _serviceProvider.GetService<IRepository<SCPSeries>>();
            var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();

            var dicModalityList = _dictionaryRepository.Where(t => t.Code == "Modality").SelectMany(t => t.ChildList.Select(c => c.Value)).ToList();
            var seriesModalityList = _seriesRepository.Where(t => _SCPStudyIdList.Contains(t.StudyId)).Select(t => new { SCPStudyId = t.StudyId, t.Modality }).ToList();

            foreach (var g in seriesModalityList.GroupBy(t => t.SCPStudyId))
            {
                var modality = string.Join('、', g.Select(t => t.Modality).Distinct().ToList());

                //特殊逻辑
                var modalityForEdit = dicModalityList.Contains(modality) ? modality : String.Empty;

                if (modality == "MR")
                {
                    modalityForEdit = "MRI";
                }

                if (modality == "PT")
                {
                    modalityForEdit = "PET";
                }
                if (modality == "PT、CT" || modality == "CT、PT")
                {
                    modalityForEdit = "PET-CT";
                }

                await _studyRepository.BatchUpdateNoTrackingAsync(t => t.Id == g.Key, u => new SCPStudy() { Modalities = modality, ModalityForEdit = modalityForEdit });

            }

            Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE}维护数据结束");
        }

        public void OnReceiveAbort(DicomAbortSource source, DicomAbortReason reason)
        {
            Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE}接收中断,中断原因:{source.ToString() + reason.ToString()}");
            /* nothing to do here */
        }


        public async void OnConnectionClosed(Exception exception)
        {
            /* nothing to do here */

            //奇怪的bug  上传的时候,用王捷修改的影像,会关闭,重新连接,导致检查id 丢失,然后状态不一致
            if (exception == null)
            {
                var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
                //将检查设置为传输结束
                await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });

                await _studyRepository.SaveChangesAndClearAllTrackingAsync();
            }

            Log.Logger.Warning($"连接关闭 {exception?.Message} {exception?.InnerException?.Message}");
        }




        public async Task<DicomCStoreResponse> OnCStoreRequestAsync(DicomCStoreRequest request)
        {

            string studyInstanceUid = request.Dataset.GetString(DicomTag.StudyInstanceUID);
            string seriesInstanceUid = request.Dataset.GetString(DicomTag.SeriesInstanceUID);
            string sopInstanceUid = request.Dataset.GetString(DicomTag.SOPInstanceUID);

            //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 ossService = _serviceProvider.GetService<IOSSService>();
            var dicomArchiveService = _serviceProvider.GetService<IDicomArchiveService>();
            var _seriesRepository = _serviceProvider.GetService<IRepository<SCPSeries>>();

            var _distributedLockProvider = _serviceProvider.GetService<IDistributedLockProvider>();

            var storeRelativePath = string.Empty;
            var ossFolderPath = $"{_trialId}/Image/PACS/{_trialSiteId}{studyInstanceUid}";


            long fileSize = 0;
            try
            {

                using (MemoryStream ms = new MemoryStream())
                {
                    await request.File.SaveAsync(ms);

                    //irc 从路径最后一截取Guid
                    storeRelativePath = await ossService.UploadToOSSAsync(ms, ossFolderPath, instanceId.ToString(), false);

                    fileSize = ms.Length;
                }

                Log.Logger.Information($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} {request.SOPInstanceUID} 上传完成 ");

            }
            catch (Exception ec)
            {
                Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} 上传异常 {ec.Message}");
            }



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

            using (await @lock.AcquireAsync())
            {
                try
                {
                    var scpStudyId = await dicomArchiveService.ArchiveDicomFileAsync(request.Dataset, _trialId, _trialSiteId, storeRelativePath, Association.CallingAE, Association.CalledAE);

                    if (!_SCPStudyIdList.Contains(scpStudyId))
                    {
                        _SCPStudyIdList.Add(scpStudyId);
                    }

                    var series = await _seriesRepository.FindAsync(seriesId);

                    //没有缩略图
                    if (series != null && string.IsNullOrEmpty(series.ImageResizePath))
                    {

                        // 生成缩略图
                        using (var memoryStream = new MemoryStream())
                        {
                            DicomImage image = new DicomImage(request.Dataset);

                            var sharpimage = image.RenderImage().AsSharpImage();
                            sharpimage.Save(memoryStream, new JpegEncoder());

                            // 上传缩略图到 OSS

                            var seriesPath = await ossService.UploadToOSSAsync(memoryStream, ossFolderPath, seriesId.ToString() + ".preview.jpg", false);

                            Console.WriteLine(seriesPath + "  Id:  " + seriesId);

                            series.ImageResizePath = seriesPath;

                        }
                    }


                    await _seriesRepository.SaveChangesAsync();
                }
                catch (Exception ex)
                {

                    Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} 传输处理异常:{ex.ToString()}");

                }

            }



            //监控信息设置
            _upload.FileCount++;
            _upload.FileSize = _upload.FileSize + fileSize;
            return new DicomCStoreResponse(request, DicomStatus.Success);
        }


        public Task OnCStoreRequestExceptionAsync(string tempFileName, Exception e)
        {
            // let library handle logging and error response
            return Task.CompletedTask;
        }


        public Task<DicomCEchoResponse> OnCEchoRequestAsync(DicomCEchoRequest request)
        {
            return Task.FromResult(new DicomCEchoResponse(request, DicomStatus.Success));
        }

    }
}