// Copyright 2020 New Relic, Inc. All rights reserved.
// SPDX-License-Identifier: Apache-2.0


using System;
using System.Linq;
using NewRelic.Agent.IntegrationTestHelpers;
using NewRelic.Agent.IntegrationTestHelpers.RemoteServiceFixtures;
using NewRelic.Testing.Assertions;
using Xunit;
using Xunit.Abstractions;


namespace NewRelic.Agent.IntegrationTests.AgentFeatures
{
    public abstract class VulnerabilityManagementTestsBase<TFixture> : NewRelicIntegrationTest<TFixture>
        where TFixture : ConsoleDynamicMethodFixture
    {
        private const string Namespace = "namespace";
        private const string PublicKeyToken = "publicKeyToken";
        private const string Sha1Checksum = "sha1Checksum";
        private const string Sha512Checksum = "sha512Checksum";
        private const string AssemblyHashCode = "assemblyHashCode";
        private const string ImplementationVendor = "Implementation-Vendor";
        private const string Copyright = "copyright";
        private const string MicrosoftName = "Microsoft";

        protected readonly TFixture _fixture;

        public VulnerabilityManagementTestsBase(TFixture fixture, ITestOutputHelper output) : base(fixture)
        {
            _fixture = fixture;
            _fixture.TestLogger = output;
            _fixture.SetTimeout(TimeSpan.FromMinutes(3));

            // the commands doesn't really matter as long as the agent starts and runs correctly.
            _fixture.AddCommand($"ApiCalls TestGetLinkingMetadata");

            _fixture.AddActions
            (
                setupConfiguration: () =>
                {
                    var configModifier = new NewRelicConfigModifier(fixture.DestinationNewRelicConfigFilePath);
                    configModifier.SetLogLevel("debug");
                    configModifier.ConfigureFasterUpdateLoadedModulesCycle(15);
                },
                exerciseApplication: () =>
                {
                    _fixture.AgentLog.WaitForLogLine(AgentLogBase.AgentConnectedLogLineRegex, TimeSpan.FromMinutes(2));
                    _fixture.AgentLog.WaitForLogLine(AgentLogBase.UpdateLoadedModulesLogLineRegex, TimeSpan.FromMinutes(2));
                }
            );

            _fixture.Initialize();
        }

        [Fact]
        public void Test()
        {
            var assemblies = _fixture.AgentLog.GetUpdateLoadedModulesAeemblies();

            // This assembly is always present and has all the items we send so we can verify that we capture everything.
            var mscorlib = assemblies.First(a => a.AssemblyName == "mscorlib.dll");

            // We can be only certain of a few bits of information, like the AssemblyName and Namespace.
            // We can check the contents of those items, but for the others we just want to make sure there is data.
            NrAssert.Multiple
            (
                () => Assert.NotEmpty(assemblies),
                () => Assert.Equal("mscorlib.dll", mscorlib.AssemblyName),
                () => Assert.False(string.IsNullOrWhiteSpace(mscorlib.AssemblyVersion)),
                () => Assert.Equal(7, mscorlib.Data.Count),

                () => Assert.True(mscorlib.Data.ContainsKey(Namespace)),
                () => Assert.Equal("mscorlib", mscorlib.Data[Namespace]),

                () => Assert.True(mscorlib.Data.ContainsKey(PublicKeyToken)),
                () => Assert.False(string.IsNullOrWhiteSpace(mscorlib.Data[PublicKeyToken])),

                () => Assert.True(mscorlib.Data.ContainsKey(Sha1Checksum)),
                () => Assert.False(string.IsNullOrWhiteSpace(mscorlib.Data[Sha1Checksum])),

                () => Assert.True(mscorlib.Data.ContainsKey(Sha512Checksum)),
                () => Assert.False(string.IsNullOrWhiteSpace(mscorlib.Data[Sha512Checksum])),

                () => Assert.True(mscorlib.Data.ContainsKey(AssemblyHashCode)),
                () => Assert.False(string.IsNullOrWhiteSpace(mscorlib.Data[AssemblyHashCode])),

                () => Assert.True(mscorlib.Data.ContainsKey(ImplementationVendor)),
                () => Assert.False(string.IsNullOrWhiteSpace(mscorlib.Data[ImplementationVendor])),
                () => Assert.Contains(MicrosoftName, mscorlib.Data[ImplementationVendor]),

                () => Assert.True(mscorlib.Data.ContainsKey(Copyright)),
                () => Assert.False(string.IsNullOrWhiteSpace(mscorlib.Data[Copyright])),
                () => Assert.Contains(MicrosoftName, mscorlib.Data[Copyright])
            );
        }
    }

    [NetFrameworkTest]
    public class VulnerabilityManagementTestsFWLatest : VulnerabilityManagementTestsBase<ConsoleDynamicMethodFixtureFWLatest>
    {
        public VulnerabilityManagementTestsFWLatest(ConsoleDynamicMethodFixtureFWLatest fixture, ITestOutputHelper output)
            : base(fixture, output)
        {
        }
    }

    [NetCoreTest]
    public class VulnerabilityManagementTestsCoreLatest : VulnerabilityManagementTestsBase<ConsoleDynamicMethodFixtureCoreLatest>
    {
        public VulnerabilityManagementTestsCoreLatest(ConsoleDynamicMethodFixtureCoreLatest fixture, ITestOutputHelper output)
            : base(fixture, output)
        {
        }
    }
}
