using FellowOakDicom;
using FellowOakDicom.Media;
using IRaCIS.Core.Application.ViewModel;
using System.Data;
using System.Text;

namespace IRaCIS.Core.Application.Helper
{

    public class StudyDIRInfo
    {
        public Guid SubjectId { get; set; }
        public bool IsTaskStudy { get; set; }

        public Guid SubjectVisitId { get; set; }
        // Study
        public Guid DicomStudyId { get; set; }

        public string PatientId { get; set; }
        public string PatientName { get; set; }
        public string PatientBirthDate { get; set; }
        public string PatientSex { get; set; }

        public string StudyInstanceUid { get; set; }
        public string StudyId { get; set; }
        public string DicomStudyDate { get; set; }
        public string DicomStudyTime { get; set; }
        public string AccessionNumber { get; set; }
        public string StudyDescription { get; set; }

        // Series
        public string SeriesInstanceUid { get; set; }
        public string Modality { get; set; }
        public string DicomSeriesDate { get; set; }
        public string DicomSeriesTime { get; set; }
        public int SeriesNumber { get; set; }
        public string SeriesDescription { get; set; }

        // Instance
        public Guid InstanceId { get; set; }
        public string SopInstanceUid { get; set; }
        public string SOPClassUID { get; set; }
        public int InstanceNumber { get; set; }
        public string MediaStorageSOPClassUID { get; set; }
        public string MediaStorageSOPInstanceUID { get; set; }
        public string TransferSytaxUID { get; set; }
    }
    public static class DicomDIRHelper
    {

        public static async Task GenerateStudyDIRAndUploadAsync(List<StudyDIRInfo> list, Dictionary<string, string> dic, string ossFolder, IOSSService _oSSService)
        {
            var mappings = new List<string>();
            int index = 1;

            var trialId = Guid.Empty;

            Guid.TryParse(ossFolder.Split('/', StringSplitOptions.RemoveEmptyEntries)[0], out trialId);

            var studyUid = list.FirstOrDefault()?.StudyInstanceUid;

            var dicomDir = new DicomDirectory();

            foreach (var item in list.OrderBy(t => t.SeriesNumber).ThenBy(t => t.InstanceNumber))
            {
                var dicomUid = DicomUID.Enumerate().FirstOrDefault(uid => uid.UID == item.TransferSytaxUID);

                if (dicomUid != null)
                {
                    var ts = DicomTransferSyntax.Query(dicomUid);

                    var dataset = new DicomDataset(ts)
                    {
                        { DicomTag.PatientID, item.PatientId ?? string.Empty },
                        { DicomTag.PatientName, item.PatientName ?? string.Empty },
                        { DicomTag.PatientBirthDate, item.PatientBirthDate ?? string.Empty },
                        { DicomTag.PatientSex, item.PatientSex ?? string.Empty },

                        { DicomTag.StudyInstanceUID, item.StudyInstanceUid ?? string.Empty },
                        { DicomTag.StudyID, item.StudyId ?? string.Empty },
                        { DicomTag.StudyDate, item.DicomStudyDate ?? string.Empty },
                        { DicomTag.StudyTime, item.DicomStudyTime ?? string.Empty },
                        { DicomTag.AccessionNumber, item.AccessionNumber ?? string.Empty },
                        { DicomTag.StudyDescription, item.StudyDescription ?? string.Empty },

                        { DicomTag.SeriesInstanceUID, item.SeriesInstanceUid ?? string.Empty },
                        { DicomTag.Modality, item.Modality ?? string.Empty },
                        { DicomTag.SeriesDate, item.DicomSeriesDate ?? string.Empty },
                        { DicomTag.SeriesTime, item.DicomSeriesTime ?? string.Empty },
                        { DicomTag.SeriesNumber, item.SeriesNumber.ToString() ?? string.Empty },
                        { DicomTag.SeriesDescription, item.SeriesDescription ?? string.Empty },

                        { DicomTag.SOPInstanceUID, item.SopInstanceUid ?? string.Empty },
                        { DicomTag.SOPClassUID, item.SOPClassUID ?? string.Empty },
                        { DicomTag.InstanceNumber, item.InstanceNumber.ToString() ?? string.Empty },
                        { DicomTag.MediaStorageSOPClassUID, item.MediaStorageSOPClassUID ?? string.Empty },
                        { DicomTag.MediaStorageSOPInstanceUID, item.MediaStorageSOPInstanceUID ?? string.Empty },
                        { DicomTag.TransferSyntaxUID, item.TransferSytaxUID ?? string.Empty },
                    };

                    var dicomFile = new DicomFile(dataset);

                    // 文件名递增格式：IM_00001, IM_00002, ...
                    string filename = $@"IMAGE\IM_{index:D5}";  // :D5 表示补足5位

                    mappings.Add($"{filename} => {item.InstanceId}");

                    dic.Add(item.InstanceId.ToString(), filename.TrimEnd('/', '\\').Split('/', '\\').Last());

                    dicomDir.AddFile(dicomFile, filename);

                    index++;
                }


            }

            //有实际的文件
            if (mappings.Count > 0)
            {
                #region 写入临时路径
                var tempFilePath = Path.GetTempFileName();

                // 保存 DICOMDIR 到临时文件  不能直接写入到流种
                await dicomDir.SaveAsync(tempFilePath);

                using (var memoryStream = new MemoryStream(File.ReadAllBytes(tempFilePath)))
                {
                    // 重置流位置
                    memoryStream.Position = 0;

                    var relativePath = await _oSSService.UploadToOSSAsync(memoryStream, ossFolder, "DICOMDIR", true, uploadInfo: new FileUploadRecordAddOrEdit() { TrialId = trialId, BatchDataType = BatchDataType.DICOMDIR });

                    dic.Add($"{studyUid}_DICOMDIR", relativePath.Split('/').Last());
                }

                //清理临时文件
                File.Delete(tempFilePath);

                #endregion

                #region 映射上传

                // 将映射写入内存流
                var mappingText = string.Join(Environment.NewLine, mappings);
                await using var mappingStream = new MemoryStream(Encoding.UTF8.GetBytes(mappingText));

                await _oSSService.UploadToOSSAsync(mappingStream, ossFolder, $"Download_{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}", false, uploadInfo: new FileUploadRecordAddOrEdit() { TrialId = trialId, BatchDataType = BatchDataType.DICOMDIR });

                #endregion
            }

        }


        public static async Task GenerateStudyDIR(List<StudyDIRInfo> list, Dictionary<string, string> dic, string? dirSavePath = null, Stream? outputStream = null)
        {
            var mappings = new List<string>();
            int index = 1;

            var trialId = Guid.Empty;


            var studyUid = list.FirstOrDefault()?.StudyInstanceUid;

            var dicomDir = new DicomDirectory();

            foreach (var item in list.OrderBy(t => t.SeriesNumber).ThenBy(t => t.InstanceNumber))
            {
                var dicomUid = DicomUID.Enumerate().FirstOrDefault(uid => uid.UID == item.TransferSytaxUID);

                if (dicomUid != null)
                {
                    var ts = DicomTransferSyntax.Query(dicomUid);

                    var dataset = new DicomDataset(ts)
                    {
                        { DicomTag.PatientID, item.PatientId ?? string.Empty },
                        { DicomTag.PatientName, item.PatientName ?? string.Empty },
                        { DicomTag.PatientBirthDate, item.PatientBirthDate ?? string.Empty },
                        { DicomTag.PatientSex, item.PatientSex ?? string.Empty },

                        { DicomTag.StudyInstanceUID, item.StudyInstanceUid ?? string.Empty },
                        { DicomTag.StudyID, item.StudyId ?? string.Empty },
                        { DicomTag.StudyDate, item.DicomStudyDate ?? string.Empty },
                        { DicomTag.StudyTime, item.DicomStudyTime ?? string.Empty },
                        { DicomTag.AccessionNumber, item.AccessionNumber ?? string.Empty },
                        { DicomTag.StudyDescription, item.StudyDescription ?? string.Empty },

                        { DicomTag.SeriesInstanceUID, item.SeriesInstanceUid ?? string.Empty },
                        { DicomTag.Modality, item.Modality ?? string.Empty },
                        { DicomTag.SeriesDate, item.DicomSeriesDate ?? string.Empty },
                        { DicomTag.SeriesTime, item.DicomSeriesTime ?? string.Empty },
                        { DicomTag.SeriesNumber, item.SeriesNumber.ToString() ?? string.Empty },
                        { DicomTag.SeriesDescription, item.SeriesDescription ?? string.Empty },

                        { DicomTag.SOPInstanceUID, item.SopInstanceUid ?? string.Empty },
                        { DicomTag.SOPClassUID, item.SOPClassUID ?? string.Empty },
                        { DicomTag.InstanceNumber, item.InstanceNumber.ToString() ?? string.Empty },
                        { DicomTag.MediaStorageSOPClassUID, item.MediaStorageSOPClassUID ?? string.Empty },
                        { DicomTag.MediaStorageSOPInstanceUID, item.MediaStorageSOPInstanceUID ?? string.Empty },
                        { DicomTag.TransferSyntaxUID, item.TransferSytaxUID ?? string.Empty },
                    };

                    var dicomFile = new DicomFile(dataset);

                    // 文件名递增格式：IM_00001, IM_00002, ...
                    string filename = $@"IMAGE\IM_{index:D5}";  // :D5 表示补足5位

                    mappings.Add($"{filename} => {item.InstanceId}");

                    dic.Add(item.InstanceId.ToString(), filename.TrimEnd('/', '\\').Split('/', '\\').Last());

                    dicomDir.AddFile(dicomFile, filename);

                    index++;
                }


            }

            //有实际的文件
            if (mappings.Count > 0)
            {
                // 保存 DICOMDIR 到临时文件  不能直接写入到流种

                if (dirSavePath.IsNotNullOrEmpty())
                {
                    await dicomDir.SaveAsync(dirSavePath);

                }
                else
                {
                    await dicomDir.SaveAsync(outputStream);
                }
            }

        }



        public static StudyDIRInfo ReadDicomDIRInfo(DicomFile dicomFile)
        {
            var dataset = dicomFile.Dataset;


            var info = new StudyDIRInfo
            {
                PatientId = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
                PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
                PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty),
                PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty),

                StudyInstanceUid = dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty),
                StudyId = dataset.GetSingleValueOrDefault(DicomTag.StudyID, string.Empty),
                DicomStudyDate = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty),
                DicomStudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty),
                AccessionNumber = dataset.GetSingleValueOrDefault(DicomTag.AccessionNumber, string.Empty),
                StudyDescription = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),

                SeriesInstanceUid = dataset.GetSingleValueOrDefault(DicomTag.SeriesInstanceUID, string.Empty),
                Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
                DicomSeriesDate = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty),
                DicomSeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty),
                SeriesNumber = dataset.GetSingleValueOrDefault(DicomTag.SeriesNumber, 1),
                SeriesDescription = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),

                SopInstanceUid = dataset.GetSingleValueOrDefault(DicomTag.SOPInstanceUID, string.Empty),
                SOPClassUID = dataset.GetSingleValueOrDefault(DicomTag.SOPClassUID, string.Empty),
                InstanceNumber = dataset.GetSingleValueOrDefault(DicomTag.InstanceNumber, 1),

                MediaStorageSOPClassUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.MediaStorageSOPClassUID, string.Empty),
                MediaStorageSOPInstanceUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.MediaStorageSOPInstanceUID, string.Empty),

                TransferSytaxUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.TransferSyntaxUID, string.Empty)
            };

            return info;
        }
    }
}
