using System.IO;
using Microsoft.Extensions.DependencyInjection;
using Speckle.Connectors.Common.Cancellation;
using Speckle.Connectors.CSiShared.HostApp;
using Speckle.Connectors.CSiShared.Operations.Send.Settings;
using Speckle.Connectors.CSiShared.Settings;
using Speckle.Connectors.CSiShared.Utils;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Models.Card.SendFilter;
using Speckle.Connectors.DUI.Settings;
using Speckle.Converters.Common;
using Speckle.Converters.CSiShared;
using Speckle.Sdk.Common;

namespace Speckle.Connectors.CSiShared.Bindings;

public sealed class CsiSharedSendBinding : ISendBinding
{
  public string Name => "sendBinding";
  public SendBindingUICommands Commands { get; }
  public IBrowserBridge Parent { get; }

  private readonly List<ISendFilter> _sendFilters;
  private readonly ICancellationManager _cancellationManager;
  private readonly ICsiApplicationService _csiApplicationService;
  private readonly ICsiConversionSettingsFactory _csiConversionSettingsFactory;
  private readonly ISendOperationManagerFactory _sendOperationManagerFactory;
  private readonly ToSpeckleSettingsManager _toSpeckleSettingsManager;

  public CsiSharedSendBinding(
    IBrowserBridge parent,
    IEnumerable<ISendFilter> sendFilters,
    ICancellationManager cancellationManager,
    ICsiConversionSettingsFactory csiConversionSettingsFactory,
    ICsiApplicationService csiApplicationService,
    ISendOperationManagerFactory sendOperationManagerFactory,
    ToSpeckleSettingsManager toSpeckleSettingsManager
  )
  {
    _sendFilters = sendFilters.ToList();
    _cancellationManager = cancellationManager;
    Parent = parent;
    Commands = new SendBindingUICommands(parent);
    _csiConversionSettingsFactory = csiConversionSettingsFactory;
    _csiApplicationService = csiApplicationService;
    _sendOperationManagerFactory = sendOperationManagerFactory;
    _toSpeckleSettingsManager = toSpeckleSettingsManager;
  }

  public List<ISendFilter> GetSendFilters() => _sendFilters;

  public List<ICardSetting> GetSendSettings() =>
    [new LoadCaseCombinationSetting([], _csiApplicationService.SapModel), new ResultTypeSetting([])];

  public async Task Send(string modelCardId)
  {
    using var manager = _sendOperationManagerFactory.Create();
    var (fileName, fileSizeBytes) = GetFileInfo();
    await manager.Process(
      Commands,
      modelCardId,
      (sp, card) =>
      {
        sp.GetRequiredService<IConverterSettingsStore<CsiConversionSettings>>()
          .Initialize(
            _csiConversionSettingsFactory.Create(
              _csiApplicationService.SapModel,
              _toSpeckleSettingsManager.GetLoadCasesAndCombinations(card),
              _toSpeckleSettingsManager.GetResultTypes(card)
            )
          );
      },
      card => card.SendFilter.NotNull().RefreshObjectIds().Select(DecodeObjectIdentifier).ToList(),
      fileName,
      fileSizeBytes
    );
  }

  private (string? fileName, long? fileBytes) GetFileInfo()
  {
    string fullPath = _csiApplicationService.SapModel.GetModelFilename(true);
    if (!File.Exists(fullPath))
    {
      return (null, null);
    }

    var fileInfo = new FileInfo(fullPath);
    return (fileInfo.Name, fileInfo.Length);
  }

  private ICsiWrapper DecodeObjectIdentifier(string encodedId)
  {
    var (type, name) = ObjectIdentifier.Decode(encodedId);
    return CsiWrapperFactory.Create(type, name);
  }

  public void CancelSend(string modelCardId)
  {
    _cancellationManager.CancelOperation(modelCardId);
  }
}
