using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using C4IT.F4SD.DisplayFormatting;
using C4IT.F4SD.SupportCaseProtocoll.Models;
using C4IT.FASD.Base;
using C4IT.FASD.Cockpit.Communication;
using C4IT.Logging;
using C4IT.MultiLanguage;
using FasdCockpitBase.Models;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.Services.ProtocollService;
using Newtonsoft.Json;
using static C4IT.Logging.cLogManager;
using static FasdDesktopUi.Basics.UserControls.QuickActionStatusMonitor;

namespace FasdDesktopUi.Basics.UiActions
{
    public class cUiLocalQuickAction : cUiQuickAction
    {
        public cFasdQuickActionLocal LocalQuickAction { get; set; }

        public cUiLocalQuickAction(cFasdQuickActionLocal quickAction) : base(quickAction)
        {
            LocalQuickAction = quickAction;
            Name = quickAction.Name;
        }

        public override async Task<cQuickActionStatusMonitorModel> GetQuickActionStatusMonitorDataAsync()
        {
            await Task.CompletedTask;

            return new cQuickActionStatusMonitorModel()
            {
                ActionName = LocalQuickAction.Names.GetValue(),
                QuickActionDefinition = LocalQuickAction,
                ActionSteps = new List<cQuickActionStatusMonitorModel.cQuickActionStep>()
                {
                    new cQuickActionStatusMonitorModel.cQuickActionStep(cMultiLanguageSupport.GetItem("QuickAction.Local.Load"), LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.running)
                },
                QuickActionParameters = LocalQuickAction.AdjustableParameters,
                RunQuickAction = ProcessActionAsync
            };
        }

        public override async Task<cDataCanvasDataModel> GetQuickActionDataAsync(cSupportCaseDataProvider dataProvider, bool isDetailedLayout)
        {
            DataProvider = dataProvider;

            var detailedDataQuickActionHistory = new cDetailedDataModel()
            {
                Heading = cMultiLanguageSupport.GetItem("DetailsPage.History"),
                FullDetailedData = new List<object>() { new List<object>() { "Status", cMultiLanguageSupport.GetItem("QuickAction.Revision.ExecutionTime") } }
            };

            //Get QuickAciton Data
            if (dataProvider != null)
            {
                var quickActionHistory = await dataProvider.QuickActionProtocollHelper.GetQuickActionHistoryAsync(LocalQuickAction.Name);

                if (quickActionHistory != null)
                    detailedDataQuickActionHistory.FullDetailedData.AddRange(quickActionHistory);
            }


            //Get Process Steps of Action
            var quickActionData = await GetQuickActionStatusMonitorDataAsync();

            //Get Recommendation
            cRecommendationDataModel recommendationData = QuickActionRecommendation?.Recommendation != null ? QuickActionRecommendation : null;

            return new cDataCanvasDataModel() { DetailedData = detailedDataQuickActionHistory, QuickActionStatusMonitorData = quickActionData, RecommendationData = recommendationData };
        }

        private cF4sdQuickActionRevision GetRevisionOutput(cExternalToolExecutorEnh.cProcessResult _result)
        {
            var retVal = new cF4sdQuickActionRevision() { Status = enumQuickActionRevisionStatus.unknown };
            try
            {
                if (!string.IsNullOrEmpty(_result.StandardOutput))
                {
                    retVal.OutputText = _result.StandardOutput;
                    if (retVal.Output != null)
                    {
                        if (retVal.Output.ErrorCode is null || retVal.Output.ErrorCode == 0)
                            retVal.Status = enumQuickActionRevisionStatus.finishedSuccessfull;
                        else
                            retVal.Status = enumQuickActionRevisionStatus.finishedWithError;
                    }
                }

                if (retVal.Status == enumQuickActionRevisionStatus.unknown)
                {
                    if (_result.ReturnCode != 0 || !string.IsNullOrEmpty(_result.StandardError))
                    {
                        retVal.Status = enumQuickActionRevisionStatus.finishedWithError;
                        retVal.Output = new cF4sdQuickActionRevision.cOutput()
                        {
                            ErrorCode = _result.ReturnCode,
                            ErrorDescription = _result.StandardError
                        };
                    }
                    else
                        retVal.Status = enumQuickActionRevisionStatus.finishedSuccessfull;
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }

            return retVal;
        }

        public override async Task<List<object>> ProcessActionAsync(CancellationToken token, Dictionary<cAdjustableParameter, object> ParameterDictionary = null)
        {
            try
            {
                var startTime = DateTime.UtcNow;

                var _actionResult = await cExternalToolExecutorEnh.StartLocalActionAsync(LocalQuickAction, DataProvider.NamedParameterEntries.ToInterfaceDictionary(), cMultiLanguageSupport.GetItem("RemoteTool.Credentials.PasswordRequest"), ParameterDictionary);

                cQuickActionOutput quickActionOutput = new cQuickActionOutputSingle(new cF4sdQuickActionRevision.cOutput() { ResultCode = enumQuickActionSuccess.unknown });
                cQuickActionOutput protocollOutput = new cQuickActionOutputSingle(new cF4sdQuickActionRevision.cOutput() { ResultCode = enumQuickActionSuccess.unknown });

                List<object> output = new List<object>();

                if (!token.IsCancellationRequested)
                {
                    var ResultRevision = GetRevisionOutput(_actionResult);

                    cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.running, enumQuickActionRevisionStatus.finishedSuccessfull);
                    cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.main, enumQuickActionRevisionStatus.finishedSuccessfull);

                    if (ResultRevision.Output == null)
                        quickActionOutput = new cQuickActionOutputSingle(new cF4sdQuickActionRevision.cOutput() { ResultCode = enumQuickActionSuccess.finished });
                    else
                    {
                        StatusMonitor.QuickActionOutputs.Add(ResultRevision.Output);
                        quickActionOutput = cQuickActionOutput.GetQuickActionOutput(ResultRevision.Output, DataProvider);
                    }

                    if (cF4SDCockpitXmlConfig.Instance.HealthCardConfig.ProtocollLanguage != null)
                    {
                        string tempLang = cMultiLanguageSupport.CurrentLanguage;
                        cMultiLanguageSupport.CurrentLanguage = cF4SDCockpitXmlConfig.Instance.HealthCardConfig.ProtocollLanguage;
                        if (ResultRevision.Output == null)
                            protocollOutput = new cQuickActionOutputSingle(new cF4sdQuickActionRevision.cOutput() { ResultCode = enumQuickActionSuccess.finished });
                        else
                            protocollOutput = cQuickActionOutput.GetQuickActionOutput(ResultRevision.Output, DataProvider);
                        cMultiLanguageSupport.CurrentLanguage = tempLang;
                    }

                    cQuickActionCopyData copyData = QuickActionProtocollEntryOutput.GetCopyData(LocalQuickAction, DataProvider, false, protocollOutput, StatusMonitor.MeasureValues);
                    QuickActionProtocollEntry protocollEntry = QuickActionProtocollEntryOutput.GetQuickActionProtocollEntry(LocalQuickAction, copyData);

                    F4SDProtocoll.Instance.Add(protocollEntry);

                    string quickActionStatus;
                    switch (ResultRevision.Status)
                    {
                        case enumQuickActionRevisionStatus.inProgress:
                            quickActionStatus = cMultiLanguageSupport.GetItem("QuickAction.Revision.Status.InProgress");
                            break;
                        case enumQuickActionRevisionStatus.finishedSuccessfull:
                            quickActionStatus = cMultiLanguageSupport.GetItem("QuickAction.Revision.Status.FinishedSuccessfull");
                            break;
                        case enumQuickActionRevisionStatus.finishedWithError:
                            quickActionStatus = cMultiLanguageSupport.GetItem("QuickAction.Revision.Status.FinishedWithError");
                            break;
                        case enumQuickActionRevisionStatus.unknown:
                        default:
                            quickActionStatus = cMultiLanguageSupport.GetItem("QuickAction.Revision.Status.Unknown");
                            break;
                    }

                    output = new List<object>() { quickActionStatus, cUtility.RawValueFormatter.GetDisplayValue(DateTime.UtcNow, RawValueType.DATETIME) };
                }
                else
                {
                    cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.main, enumQuickActionRevisionStatus.canceled);
                    cQuickActionStatusMonitorModel.cQuickActionStep.SetQuickActionStepStatuses(StatusMonitor.QuickActionData.ActionSteps, LocalQuickAction.Name, cQuickActionStatusMonitorModel.cQuickActionStep.enumActionStepType.running, enumQuickActionRevisionStatus.canceled);

                    quickActionOutput = new cQuickActionOutputSingle(new cF4sdQuickActionRevision.cOutput() { ResultCode = enumQuickActionSuccess.error, ErrorDescription = cMultiLanguageSupport.GetItem("QuickAction.Copy.Output.Cancel") });

                    if (cF4SDCockpitXmlConfig.Instance.HealthCardConfig.ProtocollLanguage != null)
                    {
                        string tempLang = cMultiLanguageSupport.CurrentLanguage;
                        cMultiLanguageSupport.CurrentLanguage = cF4SDCockpitXmlConfig.Instance.HealthCardConfig.ProtocollLanguage;
                        protocollOutput = new cQuickActionOutputSingle(new cF4sdQuickActionRevision.cOutput() { ResultCode = enumQuickActionSuccess.error, ErrorDescription = cMultiLanguageSupport.GetItem("QuickAction.Copy.Output.Cancel") });
                        cMultiLanguageSupport.CurrentLanguage = tempLang;
                    }

                    cQuickActionCopyData copyData = QuickActionProtocollEntryOutput.GetCopyData(LocalQuickAction, DataProvider, false, protocollOutput, StatusMonitor.MeasureValues);
                    QuickActionProtocollEntry protocollEntry = QuickActionProtocollEntryOutput.GetQuickActionProtocollEntry(LocalQuickAction, copyData);

                    F4SDProtocoll.Instance.Add(protocollEntry);

                    output = new List<object>() { cMultiLanguageSupport.GetItem("QuickAction.Revision.Status.Canceled"), cUtility.RawValueFormatter.GetDisplayValue(DateTime.UtcNow, RawValueType.DATETIME) };
                }

                _ = Task.Run(async () =>
                {
                    try
                    {
                        Guid? userId = DataProvider?.Identities?.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.User)?.Id;
                        Guid? computerId = DataProvider?.Identities?.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.Computer)?.Id;

                        var reportQuickActionParameter = new cF4SDQuickActionParameters()
                        {
                            CaseId = DataProvider.CaseId,
                            QuickActionId = LocalQuickAction.Id,
                            QuickActionName = LocalQuickAction.Name,
                            Paramaters = ParameterDictionary is null ? null : JsonConvert.SerializeObject(ParameterDictionary, Formatting.None),
                            Result = JsonConvert.SerializeObject(quickActionOutput.ResultCode.GetValueOrDefault().ToString(), Formatting.None),
                            ErrorCode = quickActionOutput.ErrorCode,
                            ErrorDescription = quickActionOutput.ErrorDescription,
                            Start = startTime,
                            Finish = DateTime.UtcNow,
                            UserId = userId,
                            DeviceId = computerId,
                            ExecutionType = LocalQuickAction.ExecutionType,
                            ResultType = LocalQuickAction.ResultType
                        };

                        var reportedQuickActionSuccessfully = await cFasdCockpitCommunicationBase.Instance.ReportQuickAction(reportQuickActionParameter);

                        if (reportedQuickActionSuccessfully is false)
                            LogEntry($"Failed to report QuickAction '{LocalQuickAction.Name}' for case '{reportQuickActionParameter.CaseId}' to Analytics.", LogLevels.Warning);
                    }
                    catch (Exception E)
                    {
                        LogException(E);
                    }
                });

                return output;
            }
            catch (Exception E)
            {
                LogException(E);
                return new List<object>() { cMultiLanguageSupport.GetItem("QuickAction.Revision.Status.FinishedWithError"), cUtility.RawValueFormatter.GetDisplayValue(DateTime.UtcNow, RawValueType.DATETIME) };
            }
        }
    }
}
