context: using System;
  using System.Collections.Generic;
  using System.IO;
  using System.Linq;
  using System.Threading;
  using System.Threading.Tasks;
  using FluentAssertions;
  using Lidarr.Api.V1.Albums;
  using Lidarr.Api.V1.Artist;
  using Lidarr.Api.V1.Blacklist;
  using Lidarr.Api.V1.Config;
  using Lidarr.Api.V1.DownloadClient;
  using Lidarr.Api.V1.History;
  using Lidarr.Api.V1.Profiles.Quality;
  using Lidarr.Api.V1.RootFolders;
  using Lidarr.Api.V1.Tags;
  using Microsoft.AspNetCore.SignalR.Client;
  using NLog;
  using NLog.Config;
  using NLog.Targets;
  using NUnit.Framework;
  using NzbDrone.Common.EnvironmentInfo;
  using NzbDrone.Core.MediaFiles.TrackImport.Manual;
  using NzbDrone.Core.Qualities;
  using NzbDrone.Integration.Test.Client;
  using NzbDrone.SignalR;
  using NzbDrone.Test.Common;
  using NzbDrone.Test.Common.Categories;
  using RestSharp;
  
  namespace NzbDrone.Integration.Test
  {
      [IntegrationTest]
      public abstract class IntegrationTestBase
      {
          protected RestClient RestClient { get; private set; }
  
          public ClientBase<BlacklistResource> Blacklist;
          public CommandClient Commands;
          public DownloadClientClient DownloadClients;
          public AlbumClient Albums;
          public TrackClient Tracks;
          public ClientBase<HistoryResource> History;
          public ClientBase<HostConfigResource> HostConfig;
          public IndexerClient Indexers;
          public LogsClient Logs;
          public ClientBase<NamingConfigResource> NamingConfig;
          public NotificationClient Notifications;
          public ClientBase<QualityProfileResource> Profiles;
          public ReleaseClient Releases;
          public ReleasePushClient ReleasePush;
          public ClientBase<RootFolderResource> RootFolders;
          public ArtistClient Artist;
          public ClientBase<TagResource> Tags;
          public ClientBase<AlbumResource> WantedMissing;
          public ClientBase<AlbumResource> WantedCutoffUnmet;
  
          private List<SignalRMessage> _signalRReceived;
  
          private HubConnection _signalrConnection;
  
          protected IEnumerable<SignalRMessage> SignalRMessages => _signalRReceived;
  
          public IntegrationTestBase()
          {
              new StartupContext();
  
              LogManager.Configuration = new LoggingConfiguration();
              var consoleTarget = new ConsoleTarget { Layout = "${level}: ${message} ${exception}" };
              LogManager.Configuration.AddTarget(consoleTarget.GetType().Name, consoleTarget);
              LogManager.Configuration.LoggingRules.Add(new LoggingRule("*", LogLevel.Trace, consoleTarget));
          }
  
          public string TempDirectory { get; private set; }
  
          public abstract string ArtistRootFolder { get; }
  
          protected abstract string RootUrl { get; }
  
          protected abstract string ApiKey { get; }
  
          protected abstract void StartTestTarget();
  
          protected abstract void InitializeTestTarget();
  
          protected abstract void StopTestTarget();
  
          [OneTimeSetUp]
          public void SmokeTestSetup()
          {
              StartTestTarget();
              InitRestClients();
              InitializeTestTarget();
          }
  
          protected virtual void InitRestClients()
          {
              RestClient = new RestClient(RootUrl + "api/v1/");
              RestClient.AddDefaultHeader("Authentication", ApiKey);
              RestClient.AddDefaultHeader("X-Api-Key", ApiKey);
  
              Blacklist = new ClientBase<BlacklistResource>(RestClient, ApiKey);
              Commands = new CommandClient(RestClient, ApiKey);
              DownloadClients = new DownloadClientClient(RestClient, ApiKey);
              Albums = new AlbumClient(RestClient, ApiKey);
              Tracks = new TrackClient(RestClient, ApiKey);
              History = new ClientBase<HistoryResource>(RestClient, ApiKey);
              HostConfig = new ClientBase<HostConfigResource>(RestClient, ApiKey, "config/host");
              Indexers = new IndexerClient(RestClient, ApiKey);
              Logs = new LogsClient(RestClient, ApiKey);
              NamingConfig = new ClientBase<NamingConfigResource>(RestClient, ApiKey, "config/naming");
              Notifications = new NotificationClient(RestClient, ApiKey);
              Profiles = new ClientBase<QualityProfileResource>(RestClient, ApiKey);
              Releases = new ReleaseClient(RestClient, ApiKey);
              ReleasePush = new ReleasePushClient(RestClient, ApiKey);
              RootFolders = new ClientBase<RootFolderResource>(RestClient, ApiKey);
              Artist = new ArtistClient(RestClient, ApiKey);
              Tags = new ClientBase<TagResource>(RestClient, ApiKey);
              WantedMissing = new ClientBase<AlbumResource>(RestClient, ApiKey, "wanted/missing");
              WantedCutoffUnmet = new ClientBase<AlbumResource>(RestClient, ApiKey, "wanted/cutoff");
          }
  
          [OneTimeTearDown]
          public void SmokeTestTearDown()
          {
              StopTestTarget();
          }
  
          [SetUp]
          public void IntegrationSetUp()
          {
              TempDirectory = Path.Combine(TestContext.CurrentContext.TestDirectory, "_test_" + TestBase.GetUID());
  
              // Wait for things to get quiet, otherwise the previous test might influence the current one.
              Commands.WaitAll();
          }
  
          [TearDown]
          public async Task IntegrationTearDown()
          {
              if (_signalrConnection != null)
              {
                  await _signalrConnection.StopAsync();
  
                  _signalrConnection = null;
                  _signalRReceived = new List<SignalRMessage>();
              }
  
              if (Directory.Exists(TempDirectory))
              {
                  try
                  {
                      Directory.Delete(TempDirectory, true);
                  }
                  catch
                  {
                  }
              }
          }
  
          protected void IgnoreOnMonoVersions(params string[] version_strings)
          {
              if (!PlatformInfo.IsMono)
              {
                  return;
              }
  
              var current = PlatformInfo.GetVersion();
              var versions = version_strings.Select(x => new Version(x)).ToList();
  
              if (versions.Any(x => x.Major == current.Major && x.Minor == current.Minor))
              {
                  throw new IgnoreException($"Ignored on mono {PlatformInfo.GetVersion()}");
              }
          }
  
          public string GetTempDirectory(params string[] args)
          {
              var path = Path.Combine(TempDirectory, Path.Combine(args));
  
              Directory.CreateDirectory(path);
  
              return path;
          }
  
          protected async Task ConnectSignalR()
          {
              _signalRReceived = new List<SignalRMessage>();
              _signalrConnection = new HubConnectionBuilder()
                  .WithUrl("http://localhost:8686/signalr/messages", options =>
                      {
                          options.AccessTokenProvider = () => Task.FromResult(ApiKey);
                      })
                  .Build();
  
              var cts = new CancellationTokenSource();
  
              _signalrConnection.Closed += e =>
              {
                  cts.Cancel();
                  return Task.CompletedTask;
              };
  
              _signalrConnection.On<SignalRMessage>("receiveMessage", (message) =>
              {
                  _signalRReceived.Add(message);
              });
  
              var connected = false;
              var retryCount = 0;
  
              while (!connected)
              {
                  try
                  {
                      await _signalrConnection.StartAsync();
                      connected = true;
                      break;
                  }
                  catch
                  {
                      if (retryCount > 25)
                      {
                          Assert.Fail("Couldn't establish signalR connection");
                      }
                  }
  
                  retryCount++;
                  Thread.Sleep(200);
              }
          }
  
          public static void WaitForCompletion(Func<bool> predicate, int timeout = 10000, int interval = 500)
          {
              var count = timeout / interval;
              for (var i = 0; i < count; i++)
              {
                  if (predicate())
                  {
                      return;
                  }
  
                  Thread.Sleep(interval);
              }
  
              if (predicate())
              {
                  return;
              }
  
              Assert.Fail("Timed on wait");
          }
  
          public ArtistResource EnsureArtist(string lidarrId, string artistName, bool? monitored = null)
          {
              var result = Artist.All().FirstOrDefault(v => v.ForeignArtistId == lidarrId);
  
              if (result == null)
              {
                  var lookup = Artist.Lookup("lidarr:" + lidarrId);
                  var artist = lookup.First();
                  artist.QualityProfileId = 1;
                  artist.MetadataProfileId = 1;
                  artist.Path = Path.Combine(ArtistRootFolder, artist.ArtistName);
                  artist.Monitored = true;
                  artist.AddOptions = new Core.Music.AddArtistOptions();
                  Directory.CreateDirectory(artist.Path);
  
                  result = Artist.Post(artist);
                  Commands.WaitAll();
                  WaitForCompletion(() => Tracks.GetTracksInArtist(result.Id).Count > 0);
              }
  
              var changed = false;
  
              if (result.RootFolderPath != ArtistRootFolder)
              {
                  changed = true;
                  result.RootFolderPath = ArtistRootFolder;
                  result.Path = Path.Combine(ArtistRootFolder, result.ArtistName);
              }
  
              if (monitored.HasValue)
              {
  
gt:                 if (result.Monitored != monitored.Value)