// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using Microsoft.Testing.Extensions.TrxReport.Abstractions.Serializers;
using Microsoft.Testing.Extensions.TrxReport.Resources;
using Microsoft.Testing.Platform.CommandLine;
using Microsoft.Testing.Platform.Extensions.TestHost;
using Microsoft.Testing.Platform.Helpers;
using Microsoft.Testing.Platform.IPC;
using Microsoft.Testing.Platform.IPC.Models;
using Microsoft.Testing.Platform.IPC.Serializers;

namespace Microsoft.Testing.Extensions.TrxReport.Abstractions;

internal sealed class TrxTestApplicationLifecycleCallbacks : ITestHostApplicationLifetime, IDisposable
{
    [UnsupportedOSPlatformGuard("BROWSER")]
    private readonly bool _isEnabled;

    private readonly IEnvironment _environment;

    public TrxTestApplicationLifecycleCallbacks(
        ICommandLineOptions commandLineOptionsService,
        IEnvironment environment)
    {
        _isEnabled =
           // TrxReportGenerator is enabled only when trx report is enabled
           commandLineOptionsService.IsOptionSet(TrxReportGeneratorCommandLine.TrxReportOptionName) &&
           // If crash dump is not enabled we run trx in-process only
           TrxModeHelpers.ShouldUseOutOfProcessTrxGeneration(commandLineOptionsService);

        _environment = environment;
    }

    public NamedPipeClient? NamedPipeClient { get; private set; }

    public string Uid => nameof(TrxTestApplicationLifecycleCallbacks);

    /// <inheritdoc />
    public string Version => ExtensionVersion.DefaultSemVer;

    /// <inheritdoc />
    public string DisplayName { get; } = ExtensionResources.TrxReportGeneratorDisplayName;

    /// <inheritdoc />
    public string Description { get; } = ExtensionResources.TrxReportGeneratorDescription;

    /// <inheritdoc />
    public Task<bool> IsEnabledAsync() => Task.FromResult(_isEnabled);

    public Task AfterRunAsync(int exitCode, CancellationToken cancellationToken) => Task.CompletedTask;

    public async Task BeforeRunAsync(CancellationToken cancellationToken)
    {
        cancellationToken.ThrowIfCancellationRequested();
        if (!_isEnabled)
        {
            return;
        }

        string namedPipeName = _environment.GetEnvironmentVariable(TrxEnvironmentVariableProvider.TRXNAMEDPIPENAME)
            ?? throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, ExtensionResources.TrxReportGeneratorMissingTrxNamedPipeEnvironmentVariable, TrxEnvironmentVariableProvider.TRXNAMEDPIPENAME));
        NamedPipeClient = new NamedPipeClient(namedPipeName, _environment);
        NamedPipeClient.RegisterSerializer(new ReportFileNameRequestSerializer(), typeof(ReportFileNameRequest));
        NamedPipeClient.RegisterSerializer(new TestAdapterInformationRequestSerializer(), typeof(TestAdapterInformationRequest));
        NamedPipeClient.RegisterSerializer(new TrxStreamLocationRequestSerializer(), typeof(TrxStreamLocationRequest));
        NamedPipeClient.RegisterSerializer(new VoidResponseSerializer(), typeof(VoidResponse));

        // Connect to the named pipe server
        await NamedPipeClient.ConnectAsync(cancellationToken).TimeoutAfterAsync(TimeoutHelper.DefaultHangTimeSpanTimeout, cancellationToken).ConfigureAwait(false);
    }

    public void Dispose()
    {
        if (_isEnabled)
        {
            NamedPipeClient?.Dispose();
        }
    }
}
