context: using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Net;
  using FluentValidation.Results;
  using NLog;
  using NzbDrone.Common.Disk;
  using NzbDrone.Common.Extensions;
  using NzbDrone.Common.Http;
  using NzbDrone.Core.Configuration;
  using NzbDrone.Core.Download.Clients.DownloadStation.Proxies;
  using NzbDrone.Core.Parser.Model;
  using NzbDrone.Core.RemotePathMappings;
  using NzbDrone.Core.ThingiProvider;
  using NzbDrone.Core.Validation;
  
  namespace NzbDrone.Core.Download.Clients.DownloadStation
  {
      public class UsenetDownloadStation : UsenetClientBase<DownloadStationSettings>
      {
          protected readonly IDownloadStationInfoProxy _dsInfoProxy;
          protected readonly IDownloadStationTaskProxy _dsTaskProxy;
          protected readonly ISharedFolderResolver _sharedFolderResolver;
          protected readonly ISerialNumberProvider _serialNumberProvider;
          protected readonly IFileStationProxy _fileStationProxy;
  
          public UsenetDownloadStation(ISharedFolderResolver sharedFolderResolver,
                                       ISerialNumberProvider serialNumberProvider,
                                       IFileStationProxy fileStationProxy,
                                       IDownloadStationInfoProxy dsInfoProxy,
                                       IDownloadStationTaskProxy dsTaskProxy,
                                       IHttpClient httpClient,
                                       IConfigService configService,
                                       IDiskProvider diskProvider,
                                       IRemotePathMappingService remotePathMappingService,
                                       IValidateNzbs nzbValidationService,
                                       Logger logger)
              : base(httpClient, configService, diskProvider, remotePathMappingService, nzbValidationService, logger)
          {
              _dsInfoProxy = dsInfoProxy;
              _dsTaskProxy = dsTaskProxy;
              _fileStationProxy = fileStationProxy;
              _sharedFolderResolver = sharedFolderResolver;
              _serialNumberProvider = serialNumberProvider;
          }
  
          public override string Name => "Download Station";
  
          public override ProviderMessage Message => new ProviderMessage("Lidarr is unable to connect to Download Station if 2-Factor Authentication is enabled on your DSM account", ProviderMessageType.Warning);
  
          protected IEnumerable<DownloadStationTask> GetTasks()
          {
              return _dsTaskProxy.GetTasks(Settings).Where(v => v.Type.ToLower() == DownloadStationTaskType.NZB.ToString().ToLower());
          }
  
          public override IEnumerable<DownloadClientItem> GetItems()
          {
              var nzbTasks = GetTasks();
              var serialNumber = _serialNumberProvider.GetSerialNumber(Settings);
  
              var items = new List<DownloadClientItem>();
  
              long totalRemainingSize = 0;
              long globalSpeed = nzbTasks.Where(t => t.Status == DownloadStationTaskStatus.Downloading)
                                         .Select(GetDownloadSpeed)
                                         .Sum();
  
              foreach (var nzb in nzbTasks)
              {
                  var outputPath = new OsPath($"/{nzb.Additional.Detail["destination"]}");
  
                  var taskRemainingSize = GetRemainingSize(nzb);
  
                  if (nzb.Status != DownloadStationTaskStatus.Paused)
                  {
                      totalRemainingSize += taskRemainingSize;
                  }
  
                  if (Settings.TvDirectory.IsNotNullOrWhiteSpace())
                  {
                      if (!new OsPath($"/{Settings.TvDirectory}").Contains(outputPath))
                      {
                          continue;
                      }
                  }
                  else if (Settings.MusicCategory.IsNotNullOrWhiteSpace())
                  {
                      var directories = outputPath.FullPath.Split('\\', '/');
                      if (!directories.Contains(Settings.MusicCategory))
                      {
                          continue;
                      }
                  }
  
                  var item = new DownloadClientItem()
                  {
                      Category = Settings.MusicCategory,
                      DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
                      DownloadId = CreateDownloadId(nzb.Id, serialNumber),
                      Title = nzb.Title,
                      TotalSize = nzb.Size,
                      RemainingSize = taskRemainingSize,
                      Status = GetStatus(nzb),
                      Message = GetMessage(nzb),
                      CanBeRemoved = true,
                      CanMoveFiles = true
                  };
  
                  if (item.Status != DownloadItemStatus.Paused)
                  {
                      item.RemainingTime = GetRemainingTime(totalRemainingSize, globalSpeed);
                  }
  
                  if (item.Status == DownloadItemStatus.Completed || item.Status == DownloadItemStatus.Failed)
                  {
                      item.OutputPath = GetOutputPath(outputPath, nzb, serialNumber);
                  }
  
                  items.Add(item);
              }
  
              return items;
          }
  
          protected OsPath GetOutputPath(OsPath outputPath, DownloadStationTask task, string serialNumber)
          {
              var fullPath = _sharedFolderResolver.RemapToFullPath(outputPath, Settings, serialNumber);
  
              var remotePath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, fullPath);
  
              var finalPath = remotePath + task.Title;
  
              return finalPath;
          }
  
          public override DownloadClientInfo GetStatus()
          {
              try
              {
                  var serialNumber = _serialNumberProvider.GetSerialNumber(Settings);
                  var sharedFolder = GetDownloadDirectory() ?? GetDefaultDir();
                  var outputPath = new OsPath($"/{sharedFolder.TrimStart('/')}");
                  var path = _sharedFolderResolver.RemapToFullPath(outputPath, Settings, serialNumber);
  
                  return new DownloadClientInfo
                  {
                      IsLocalhost = Settings.Host == "127.0.0.1" || Settings.Host == "localhost",
                      OutputRootFolders = new List<OsPath> { _remotePathMappingService.RemapRemoteToLocal(Settings.Host, path) }
                  };
              }
              catch (DownloadClientException e)
              {
                  _logger.Debug(e, "Failed to get config from Download Station");
  
                  throw;
              }
          }
  
          public override void RemoveItem(string downloadId, bool deleteData)
          {
              if (deleteData)
              {
                  DeleteItemData(downloadId);
              }
  
              _dsTaskProxy.RemoveTask(ParseDownloadId(downloadId), Settings);
              _logger.Debug("{0} removed correctly", downloadId);
          }
  
          protected override string AddFromNzbFile(RemoteAlbum remoteAlbum, string filename, byte[] fileContent)
          {
              var hashedSerialNumber = _serialNumberProvider.GetSerialNumber(Settings);
  
              _dsTaskProxy.AddTaskFromData(fileContent, filename, GetDownloadDirectory(), Settings);
  
              var items = GetTasks().Where(t => t.Additional.Detail["uri"] == filename);
  
              var item = items.SingleOrDefault();
  
              if (item != null)
              {
                  _logger.Debug("{0} added correctly", remoteAlbum);
                  return CreateDownloadId(item.Id, hashedSerialNumber);
              }
  
              _logger.Debug("No such task {0} in Download Station", filename);
  
              throw new DownloadClientException("Failed to add NZB task to Download Station");
          }
  
          protected override void Test(List<ValidationFailure> failures)
          {
              failures.AddIfNotNull(TestConnection());
              if (failures.HasErrors())
              {
                  return;
              }
  
              failures.AddIfNotNull(TestOutputPath());
              failures.AddIfNotNull(TestGetNZB());
          }
  
          protected ValidationFailure TestOutputPath()
          {
              try
              {
                  var downloadDir = GetDefaultDir();
  
                  if (downloadDir == null)
                  {
                      return new NzbDroneValidationFailure(nameof(Settings.TvDirectory), "No default destination")
                      {
                          DetailedDescription = $"You must login into your Diskstation as {Settings.Username} and manually set it up into DownloadStation settings under BT/HTTP/FTP/NZB -> Location."
                      };
                  }
  
                  downloadDir = GetDownloadDirectory();
  
                  if (downloadDir != null)
                  {
                      var sharedFolder = downloadDir.Split('\\', '/')[0];
                      var fieldName = Settings.TvDirectory.IsNotNullOrWhiteSpace() ? nameof(Settings.TvDirectory) : nameof(Settings.MusicCategory);
  
                      var folderInfo = _fileStationProxy.GetInfoFileOrDirectory($"/{downloadDir}", Settings);
  
                      if (folderInfo.Additional == null)
                      {
                          return new NzbDroneValidationFailure(fieldName, $"Shared folder does not exist")
                          {
                              DetailedDescription = $"The Diskstation does not have a Shared Folder with the name '{sharedFolder}', are you sure you specified it correctly?"
                          };
                      }
  
                      if (!folderInfo.IsDir)
                      {
                          return new NzbDroneValidationFailure(fieldName, $"Folder does not exist")
                          {
                              DetailedDescription = $"The folder '{downloadDir}' does not exist, it must be created manually inside the Shared Folder '{sharedFolder}'."
                          };
                      }
                  }
  
                  return null;
              }
              catch (DownloadClientAuthenticationException ex)
              {
                  // User could not have permission to access to downloadstation
                  _logger.Error(ex, "Unable to authenticate");
                  return new NzbDroneValidationFailure(string.Empty, ex.Message);
              }
              catch (Exception ex)
              {
                  _logger.Error(ex, "Error testing Usenet Download Station");
                  return new NzbDroneValidationFailure(string.Empty, $"Unknown exception: {ex.Message}");
              }
          }
  
          protected ValidationFailure TestConnection()
          {
              try
              {
                  return ValidateVersion();
              }
              catch (DownloadClientAuthenticationException ex)
              {
                  _logger.Error(ex, "Unable to authenticate");
                  return new NzbDroneValidationFailure("Username", "Authentication failure")
                  {
                      DetailedDescription = $"Please verify your username and password. Also verify if the host running Lidarr isn't blocked from accessing {Name} by WhiteList limitations in the {Name} configuration."
                  };
              }
              catch (WebException ex)
              {
                  _logger.Error(ex, "Unable to connect to Usenet Download Station");
  
                  if (ex.Status == WebExceptionStatus.ConnectFailure)
                  {
                      return new NzbDroneValidationFailure("Host", "Unable to connect")
                      {
                          DetailedDescription = "Please verify the hostname and port."
                      };
                  }
  
                  return new NzbDroneValidationFailure(string.Empty, "Unknown exception: " + ex.Message);
              }
              catch (Exception ex)
              {
                  _logger.Error(ex, "Error testing Torrent Download Station");
  
                  return new NzbDroneValidationFailure("Host", "Unable to connect to Usenet Download Station")
                         {
                             DetailedDescription = ex.Message
                         };
              }
          }
  
          protected ValidationFailure ValidateVersion()
          {
  
gt:             var info = _dsTaskProxy.GetApiInfo(Settings);