using System;
using System.Threading.Tasks;
using C4IT.LIAM;
using Newtonsoft.Json;

namespace LiamWorkflowDiagnostics
{
    internal class ProviderTestSession
    {
        private readonly Action<string> _log;

        public ProviderTestSession(Action<string> log)
        {
            _log = log ?? throw new ArgumentNullException(nameof(log));
        }

        public cLiamProviderBase Provider { get; private set; }
        public cLiamProviderData ProviderData { get; private set; }
        public string SanitizedConfigJson { get; private set; }
        public string ProviderConfigId { get; private set; }
        public string ProviderConfigObjectId { get; private set; }

        public async Task<bool> InitializeAsync(cLiamProviderData data, string maskToken, Func<cLiamProviderData, cLiamProviderBase> factory, string providerConfigId = null, string providerConfigObjectId = null)
        {
            if (data == null)
                throw new ArgumentNullException(nameof(data));
            if (factory == null)
                throw new ArgumentNullException(nameof(factory));

            ProviderData = Clone(data);
            SanitizedConfigJson = BuildSanitizedJson(ProviderData, maskToken);
            _log("Sanitisiertes Provider-Setup:");
            _log(SanitizedConfigJson);

            ProviderConfigId = string.IsNullOrWhiteSpace(providerConfigId) ? null : providerConfigId;
            ProviderConfigObjectId = string.IsNullOrWhiteSpace(providerConfigObjectId) ? null : providerConfigObjectId;

            if (!string.IsNullOrWhiteSpace(ProviderConfigId))
                _log($"Config Class ID: {ProviderConfigId}");
            if (!string.IsNullOrWhiteSpace(ProviderConfigObjectId))
                _log($"Config Object ID: {ProviderConfigObjectId}");

            Provider = factory(ProviderData);
            if (Provider == null)
            {
                _log("Provider-Fabrik lieferte kein Objekt. Prüfe Provider-Typ und Assemblies.");
                return false;
            }

            var success = await Provider.LogonAsync().ConfigureAwait(false);
            if (!success)
            {
                if (Provider is cLiamProviderExchange exchangeProvider)
                    _log($"Logon fehlgeschlagen [{exchangeProvider.GetLastErrorCode()}]: {Provider.GetLastErrorMessage()}");
                else
                    _log($"Logon fehlgeschlagen: {Provider.GetLastErrorMessage()}");
            }
            else
                _log("Logon erfolgreich.");

            return success;
        }

        public static string BuildSanitizedJson(cLiamProviderData data, string maskToken)
        {
            if (data == null)
                throw new ArgumentNullException(nameof(data));

            var clone = Clone(data);
            if (clone.Credential != null)
                clone.Credential.Secret = string.IsNullOrWhiteSpace(maskToken) ? "***" : maskToken;

            return JsonConvert.SerializeObject(clone, Formatting.Indented);
        }

        private static cLiamProviderData Clone(cLiamProviderData data)
        {
            var serialized = JsonConvert.SerializeObject(data);
            return JsonConvert.DeserializeObject<cLiamProviderData>(serialized);
        }
    }
}
