using Dicom;
using FISLib.Connect;
using FISLib.Remedical;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using Vinno.FIS.Sonopost.Common;
using Vinno.FIS.Sonopost.Features.Dicom;
using Vinno.FIS.Sonopost.Helpers;
using Vinno.FIS.Sonopost.Managers.Interfaces;
using Vinno.IUS.Common.Log;

namespace Vinno.FIS.Sonopost.Managers
{
    internal class RemedicalManager : SonopostManager, IRemedicalManager
    {
        private readonly IRemedicalService _fisRemedicalService;
        private readonly ILoginManager _loginManager;

        public RemedicalManager()
        {
            _loginManager = AppManager.Instance.GetManager<ILoginManager>();
            _loginManager.LoginStatusChanged += OnLoginStatusChanged;
            _fisRemedicalService = AppManager.Instance.GetManager<IFISManager>().FISRemedicalService;
            _fisRemedicalService.FISScanDataChanged += OnFISScanDataChanged;
        }

        private void OnFISScanDataChanged(object sender, FISVidDataChangedEventArgs e)
        {
            try
            {
                var scanDataId = e.FISVidData.Id;
                Logger.WriteLineInfo($"Scan data id: {scanDataId},Status:{e.FISVidData?.Status},ChangeType:{e.ChangeType}");
                if (e.FISVidData.Status == FISUploadStatus.Fail && e.ChangeType == FISVidDataChangeType.Update)
                {
                    DicomUploadContextOperator.Instance.UpdateStatusByScanId(scanDataId, DicomUploadStatus.UploadFail);
                }
                else if (e.FISVidData.Status == FISUploadStatus.FailBecauseExamIsFinished && e.ChangeType == FISVidDataChangeType.Update)
                {
                    DicomUploadContextOperator.Instance.UpdateStatusByScanId(scanDataId, DicomUploadStatus.UploadFailBecauseExamIsFinished);
                }
                else if ((e.FISVidData.Status == FISUploadStatus.Uploaded && e.ChangeType == FISVidDataChangeType.Removed) || e.FISVidData.Status == FISUploadStatus.Deleted && e.ChangeType == FISVidDataChangeType.Update)
                {
                    var item = DicomUploadContextOperator.Instance.GetCacheByScanId(scanDataId);
                    if (item == null)
                    {
                        return;
                    }
                    RemoveByScanDataId(scanDataId);
                    FileHelper.DeleteFile(item.DicomPath);
                }
                else if (e.FISVidData.Status == FISUploadStatus.Uploading && e.ChangeType == FISVidDataChangeType.Update)
                {
                    DicomUploadContextOperator.Instance.UpdateStatusByScanId(scanDataId, DicomUploadStatus.Uploading);
                }
                else if ((e.FISVidData.Status == FISUploadStatus.Waiting || e.FISVidData.Status == FISUploadStatus.Idle) && (e.ChangeType == FISVidDataChangeType.Update || e.ChangeType == FISVidDataChangeType.Added))
                {
                    DicomUploadContextOperator.Instance.UpdateStatusByScanId(scanDataId, DicomUploadStatus.Waiting);
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLineError($"On scan data changed error {e.ChangeType} - {e.FISVidData.Id} : {ex}");
            }
        }

        /// <summary>
        /// Delete OverDueRecords
        /// </summary>
        /// <param name="tempFileDays"></param>
        public void DeleteOverDueRecords(int tempFileDays)
        {
            if (_loginManager.DeviceStatus != DeviceStatus.Logon)
            {
                return;
            }
            var failList = DicomUploadContextOperator.Instance.GetAll();

            var failScanDatas = _fisRemedicalService.LoadFailedScanDatas();
            if (failScanDatas != null && failList != null)
            {
                foreach (var failScanData in failScanDatas)
                {
                    if (!failList.Any(x => x.ScanId == failScanData.Id))
                    {
                        _fisRemedicalService.DeleteScanDataById(failScanData.Id);
                    }
                }
            }
        }

        /// <summary>
        /// upload dicom
        /// </summary>
        /// <param name="uploadVidPath"></param>
        /// <param name="patientId"></param>
        public void UploadWorkFlow(string uploadVidPath, string patientId)
        {
            Logger.WriteLineInfo($"Start Upload to Server,patientId:{patientId}");
            var content = UploadContent.Parse(uploadVidPath);
            if (content != null)
            {
                try
                {
                    if (!content.IsVidFile)
                    {
                        var originalDicomPath = Path.Combine(SonopostConstants.DataFolder, SonopostConstants.OriginalDicomFolder, content.Date, $"{content.Id}.{SonopostConstants.DicomFileName}");
                        if (File.Exists(originalDicomPath))
                        {
                            var dicomFile = DicomFile.Open(originalDicomPath);
                            var patientInfo = PatientScanInfoHelper.CreatePatientScanInfo(dicomFile.Dataset);
                            var examId = dicomFile.Dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty);
                            if (_loginManager.DeviceStatus != DeviceStatus.Logon)
                            {
                                DicomUploadContextOperator.Instance.UpdateStatus(content.Id, DicomUploadStatus.CreateScanDataFail);
                                Logger.WriteLineError($"Upload vinno dicom file failed,Because the Remedical is null.PatientId:{patientId},OriginalDicomPath:{originalDicomPath}");
                                return;
                            }
                            var scanDataId = _fisRemedicalService.UploadScanData(null, examId, string.Empty, content.UploadFilePath, content.VidType, "FromSonopost", patientInfo, string.Empty);
                            if (!string.IsNullOrEmpty(scanDataId))
                            {
                                DicomUploadContextOperator.Instance.UpdateScanId(content.Id, scanDataId);
                                return;
                            }
                            else
                            {
                                DicomUploadContextOperator.Instance.UpdateStatus(content.Id, DicomUploadStatus.CreateScanDataFail);
                                Logger.WriteLineError($"ScanData is null.PatientId:{patientId},OriginalDicomPath:{originalDicomPath}");
                                return;
                            }
                        }
                        else
                        {
                            throw new Exception($"Original Dicom File is not exist {originalDicomPath}");
                        }
                    }
                    else
                    {
                        if (_loginManager.DeviceStatus != DeviceStatus.Logon)
                        {
                            DicomUploadContextOperator.Instance.UpdateStatus(content.Id, DicomUploadStatus.CreateScanDataFail);
                            Logger.WriteLineError($"Upload vinno dicom file failed,Because the Remedical is null.PatientId:{patientId}");
                            return;
                        }
                        string scanDataId;
                        scanDataId = _fisRemedicalService.UploadScanData(null, "ExamIdOnlyForScreenShotVersion", string.Empty, content.UploadFilePath, content.VidType, "FromSonopost", new FISPatientScanInfo(), content.ExamRecordId, null, null, true);
                        if (!string.IsNullOrEmpty(scanDataId))
                        {
                            DicomUploadContextOperator.Instance.UpdateScanId(content.Id, scanDataId);
                            return;
                        }
                        else
                        {
                            DicomUploadContextOperator.Instance.UpdateStatus(content.Id, DicomUploadStatus.CreateScanDataFail);
                            Logger.WriteLineError($"ScanData is null.PatientId:{patientId},ExanRecordId:{content.ExamRecordId}");
                            return;
                        }
                    }
                }
                catch (Exception ex)
                {
                    DicomUploadContextOperator.Instance.UpdateStatus(content.Id, DicomUploadStatus.Unknown);
                    Logger.WriteLineError($"Upload vinno dicom file failed,PatientId:{patientId}:{ex}.");
                }
            }
            else
            {
                Logger.WriteLineError("Parse Upload content Fail");
            }
        }

        public void Delete(string id)
        {
            try
            {
                var item = DicomUploadContextOperator.Instance.GetCacheById(id);
                if (item == null)
                {
                    return;
                }
                if (string.IsNullOrEmpty(item.ScanId))
                {
                    RemoveById(id);
                }
                else
                {
                    if (_loginManager.DeviceStatus == DeviceStatus.Logon)
                    {
                        _fisRemedicalService.DeleteScanDataById(item.ScanId);
                    }
                    RemoveByScanDataId(item.ScanId);
                }
                FileHelper.DeleteFile(item.DicomPath);
            }
            catch (Exception ex)
            {
                Logger.WriteLineError($"RemedicalManager Delete Error:{ex}");
            }
        }

        public void Retry(string id)
        {
            var retryItem = DicomUploadContextOperator.Instance.GetCacheById(id);
            if (retryItem == null)
                return;
            if (retryItem.Status == DicomUploadStatus.ConvertFail)
            {
                Logger.WriteLineWarn($"Convert Fail,Can not Retry,DicomPath:{retryItem.DicomPath}");
                return;
            }
            else if (retryItem.Status == DicomUploadStatus.CreateScanDataFail)
            {
                var count = retryItem.Count + 1;
                DicomUploadContextOperator.Instance.UpdateRetryCount(retryItem, count);
                Thread.Sleep(1000);
                DicomUploadContextOperator.Instance.UpdateStatus(id, DicomUploadStatus.Waiting);
                UploadWorkFlow(retryItem.VidPath, retryItem.PatientId);
            }
            else if (retryItem.Status == DicomUploadStatus.UploadFail || retryItem.Status == DicomUploadStatus.UploadFailBecauseExamIsFinished)
            {
                var count = retryItem.Count + 1;
                DicomUploadContextOperator.Instance.UpdateRetryCount(retryItem, count);
                Thread.Sleep(1000);
                DicomUploadContextOperator.Instance.UpdateStatus(id, DicomUploadStatus.Waiting);
                RetryUploadByScanId(retryItem.ScanId);
            }
        }

        public string GetDicomFilePath(string id)
        {
            var cache = DicomUploadContextOperator.Instance.GetCacheById(id);
            if (cache != null)
            {
                return cache.DicomPath;
            }
            return string.Empty;
        }

        public IList<DicomUploadContext> GetConvertFailContexts()
        {
            return DicomUploadContextOperator.Instance.GetAll();
        }

        private void RetryUploadByScanId(string scanDataId)
        {
            if (_loginManager.DeviceStatus != DeviceStatus.Logon)
            {
                Logger.WriteLineError($"Reupload vinno dicom file failed,Because the Remedical is null.");
                return;
            }
            var scanData = _fisRemedicalService.LoadFailedScanDatas().FirstOrDefault(m => m.Id == scanDataId);
            if (scanData != null)
            {
                Reupload(scanData.Id);
            }
            else
            {
                Logger.WriteLineError($"RetryUploadByScanId Can't find ScanDataId{scanDataId} and Delete Automatically");
                var item = DicomUploadContextOperator.Instance.GetCacheByScanId(scanDataId);
                if (item == null)
                {
                    return;
                }
                RemoveByScanDataId(scanDataId);
                FileHelper.DeleteFile(item.DicomPath);
            }
        }

        private void Reupload(string scanDataId)
        {
            _fisRemedicalService.ReUploadScanDataByIds(new List<string> { scanDataId });
        }

        private void RemoveByScanDataId(string scanDataId)
        {
            DicomUploadContextOperator.Instance.DeleteByScanId(scanDataId);
        }

        private void RemoveById(string id)
        {
            DicomUploadContextOperator.Instance.DeleteById(id);
        }

        public string GetCollcetingRecordCode()
        {
            if (_loginManager.DeviceStatus != DeviceStatus.Logon)
            {
                Logger.WriteLineError($"GetCollcetingRecordCode failed,please connect the vcloud server first.");
                return null;
            }
            return _fisRemedicalService.GetCollcetingRecordCode();
        }

        /// <summary>
        /// 根据ExamrocordId获取详细检查信息
        /// </summary>
        /// <param name="examRecordId"></param>
        /// <returns></returns>
        public FISvCloudExamInfo GetCloudExamInfo(string examRecordId)
        {
            if (_loginManager.DeviceStatus != DeviceStatus.Logon)
            {
                Logger.WriteLineError($"GetCloudExamInfo failed,please connect the vcloud server first.");
                return null;
            }
            return _fisRemedicalService.GetvCloudExamInfo(examRecordId);
        }

        public void ClearRemedicalCache()
        {
            try
            {
                if (_loginManager.DeviceStatus == DeviceStatus.Logon)
                {
                    _fisRemedicalService.ClearExamRecorderCache(); ;
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLineError($"LivePushManager ClearRemedicalCache Error:{ex}");
            }
        }

        public override void DoDispose()
        {
            try
            {
                _loginManager.LoginStatusChanged -= OnLoginStatusChanged;
                _fisRemedicalService.FISScanDataChanged -= OnFISScanDataChanged;
            }
            catch (Exception ex)
            {
                Logger.WriteLineError($"RemedicalManager DoDispose Error:{ex}");
            }
            base.DoDispose();
        }

        private void OnLoginStatusChanged(object sender, DeviceStatus e)
        {
            switch (e)
            {
                case DeviceStatus.Logon:
                    ReUploadAll();
                    break;
            }
        }

        private void ReUploadAll()
        {
            try
            {
                if (_loginManager.DeviceStatus == DeviceStatus.Logon)
                {
                    var failList = _fisRemedicalService.LoadFailedScanDatas();
                    if (failList != null)
                    {
                        foreach (var fail in failList)
                        {
                            RetryUploadByScanId(fail.Id);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLineError($"RemedicalManager DoDispose Error:{ex}");
            }
            base.DoDispose();
        }
    }
}