context: using System;
  using System.Collections.Generic;
  using System.Diagnostics;
  using System.Linq;
  using System.Net;
  using System.Text;
  using System.Threading.Tasks;
  using System.Xml.Linq;
  using Jackett.Common;
  using Jackett.Common.Indexers;
  using Jackett.Common.Indexers.Meta;
  using Jackett.Common.Models;
  using Jackett.Common.Models.DTO;
  using Jackett.Common.Services.Interfaces;
  using Jackett.Common.Utils;
  using Microsoft.AspNetCore.Authorization;
  using Microsoft.AspNetCore.Mvc;
  using Microsoft.AspNetCore.Mvc.Filters;
  using Microsoft.AspNetCore.Routing;
  using NLog;
  
  namespace Jackett.Server.Controllers
  {
      public class RequiresApiKey : IActionFilter
      {
          public IServerService serverService;
  
          public RequiresApiKey(IServerService ss) => serverService = ss;
  
          public void OnActionExecuting(ActionExecutingContext context)
          {
              var validApiKey = serverService.GetApiKey();
              var queryParams = context.HttpContext.Request.Query;
              var queryApiKey = queryParams.Where(x => x.Key == "apikey" || x.Key == "passkey").Select(x => x.Value).FirstOrDefault();
  
  #if DEBUG
              if (Debugger.IsAttached)
              {
                  return;
              }
  #endif
              if (queryApiKey != validApiKey)
              {
                  context.Result = ResultsController.GetErrorActionResult(context.RouteData, HttpStatusCode.Unauthorized, 100, "Invalid API Key");
              }
          }
  
          public void OnActionExecuted(ActionExecutedContext context)
          {
              // do something after the action executes
          }
      }
  
      public class RequiresConfiguredIndexer : IActionFilter
      {
          public void OnActionExecuting(ActionExecutingContext context)
          {
              var controller = context.Controller;
              if (!(controller is IIndexerController))
                  return;
  
              var indexerController = controller as IIndexerController;
  
              var parameters = context.RouteData.Values;
  
              if (!parameters.ContainsKey("indexerId"))
              {
                  indexerController.CurrentIndexer = null;
                  context.Result = ResultsController.GetErrorActionResult(context.RouteData, HttpStatusCode.NotFound, 200, "Indexer is not specified");
                  return;
              }
  
              var indexerId = parameters["indexerId"] as string;
              if (string.IsNullOrWhiteSpace(indexerId))
              {
                  indexerController.CurrentIndexer = null;
                  context.Result = ResultsController.GetErrorActionResult(context.RouteData, HttpStatusCode.NotFound, 201, "Indexer is not specified (empty value)");
                  return;
              }
  
              var indexerService = indexerController.IndexerService;
              var indexer = indexerService.GetIndexer(indexerId);
  
              if (indexer == null)
              {
                  indexerController.CurrentIndexer = null;
                  context.Result = ResultsController.GetErrorActionResult(context.RouteData, HttpStatusCode.NotFound, 201, "Indexer is not supported");
                  return;
              }
  
              if (!indexer.IsConfigured)
              {
                  indexerController.CurrentIndexer = null;
                  context.Result = ResultsController.GetErrorActionResult(context.RouteData, HttpStatusCode.NotFound, 201, "Indexer is not configured");
                  return;
              }
  
              indexerController.CurrentIndexer = indexer;
          }
  
          public void OnActionExecuted(ActionExecutedContext context)
          {
              // do something after the action executes
          }
      }
  
      public class RequiresValidQuery : IActionFilter
      {
          public void OnActionExecuting(ActionExecutingContext context)
          {
              //TODO: Not sure what this is meant to do
              //if (context.HttpContext.Response != null)
              //    return;
  
              var controller = context.Controller;
              if (!(controller is IResultController))
              {
                  return;
              }
  
              var resultController = controller as IResultController;
  
              var query = context.ActionArguments.First().Value;
              var queryType = query.GetType();
              var converter = queryType.GetMethod("ToTorznabQuery", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);
              if (converter == null)
              {
                  context.Result = ResultsController.GetErrorActionResult(context.RouteData, HttpStatusCode.BadRequest, 900, "ToTorznabQuery() not found");
              }
  
              var converted = converter.Invoke(null, new object[] { query });
              var torznabQuery = converted as TorznabQuery;
              resultController.CurrentQuery = torznabQuery;
  
              if (queryType == typeof(ApiSearch)) // Skip CanHandleQuery() check for manual search (CurrentIndexer isn't used during manul search)
              {
                  return;
              }
  
              if (!resultController.CurrentIndexer.CanHandleQuery(resultController.CurrentQuery))
              {
                  context.Result = ResultsController.GetErrorActionResult(context.RouteData, HttpStatusCode.BadRequest, 201, $"{resultController.CurrentIndexer.Id} " +
                      $"does not support the requested query. Please check the capabilities (t=caps) and make sure the search mode and categories are supported.");
  
              }
          }
  
          public void OnActionExecuted(ActionExecutedContext context)
          {
              // do something after the action executes
          }
      }
  
      public interface IResultController : IIndexerController
      {
          TorznabQuery CurrentQuery { get; set; }
      }
  
      [AllowAnonymous]
      [ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
      [Route("api/v2.0/indexers/{indexerId}/results")]
      [TypeFilter(typeof(RequiresApiKey))]
      [TypeFilter(typeof(RequiresConfiguredIndexer))]
      [TypeFilter(typeof(RequiresValidQuery))]
      public class ResultsController : Controller, IResultController
      {
          public IIndexerManagerService IndexerService { get; private set; }
          public IIndexer CurrentIndexer { get; set; }
          public TorznabQuery CurrentQuery { get; set; }
          private readonly Logger logger;
          private readonly IServerService serverService;
          private readonly ICacheService cacheService;
          private readonly Common.Models.Config.ServerConfig serverConfig;
  
          public ResultsController(IIndexerManagerService indexerManagerService, IServerService ss, ICacheService c, Logger logger, Common.Models.Config.ServerConfig sConfig)
          {
              IndexerService = indexerManagerService;
              serverService = ss;
              cacheService = c;
              this.logger = logger;
              serverConfig = sConfig;
          }
  
          [Route("")]
          [HttpGet]
          public async Task<IActionResult> Results([FromQuery] ApiSearch requestt)
          {
              //TODO: Better way to parse querystring
  
              var request = new ApiSearch();
  
              foreach (var t in Request.Query)
              {
                  if (t.Key == "Tracker[]")
                  {
                      request.Tracker = t.Value.ToString().Split(',');
                  }
  
                  if (t.Key == "Category[]")
                  {
                      request.Category = t.Value.ToString().Split(',').Select(int.Parse).ToArray();
                      CurrentQuery.Categories = request.Category;
                  }
  
                  if (t.Key == "query")
                  {
                      request.Query = t.Value.ToString();
                  }
              }
  
              var manualResult = new ManualSearchResult();
              var trackers = IndexerService.GetAllIndexers().ToList().Where(t => t.IsConfigured);
              if (request.Tracker != null)
              {
                  trackers = trackers.Where(t => request.Tracker.Contains(t.Id));
              }
  
              trackers = trackers.Where(t => t.CanHandleQuery(CurrentQuery));
  
              var tasks = trackers.ToList().Select(t => t.ResultsForQuery(CurrentQuery)).ToList();
              try
              {
  
gt:                 var aggregateTask = Task.WhenAll(tasks);