// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

using System;
using System.IO;
using AWS.Deploy.CLI.Utilities;
using AWS.Deploy.Common.DeploymentManifest;
using AWS.Deploy.Common.IO;
using AWS.Deploy.Orchestration;
using Xunit;
using Task = System.Threading.Tasks.Task;
using Should;
using AWS.Deploy.CLI.Common.UnitTests.IO;
using AWS.Deploy.CLI.IntegrationTests.Services;
using AWS.Deploy.Common.Recipes;
using Moq;
using AWS.Deploy.Common.Recipes.Validation;

namespace AWS.Deploy.CLI.IntegrationTests.SaveCdkDeploymentProject
{
    public class CustomRecipeLocatorTests : IDisposable
    {
        private readonly CommandLineWrapper _commandLineWrapper;
        private readonly InMemoryInteractiveService _inMemoryInteractiveService;

        public CustomRecipeLocatorTests()
        {
            _inMemoryInteractiveService = new InMemoryInteractiveService();
            _commandLineWrapper = new CommandLineWrapper(_inMemoryInteractiveService);        }

        [Fact]
        public async Task LocateCustomRecipePathsWithManifestFile()
        {
            var tempDirectoryPath = new TestAppManager().GetProjectPath(string.Empty);
            var webAppWithDockerFilePath = Path.Combine(tempDirectoryPath, "testapps", "WebAppWithDockerFile");
            var webAppWithDockerCsproj = Path.Combine(webAppWithDockerFilePath, "WebAppWithDockerFile.csproj");
            var solutionDirectoryPath = tempDirectoryPath;
            var recipeHandler = BuildRecipeHandler();
            await _commandLineWrapper.Run("git init", tempDirectoryPath);

            // ARRANGE - Create 2 CDK deployment projects that contain the custom recipe snapshot
            await Utilities.CreateCDKDeploymentProject(webAppWithDockerFilePath, Path.Combine(tempDirectoryPath, "MyCdkApp1"));
            await Utilities.CreateCDKDeploymentProject(webAppWithDockerFilePath, Path.Combine(tempDirectoryPath, "MyCdkApp2"));

            // ACT - Fetch custom recipes corresponding to the same target application that has a deployment-manifest file.
            var customRecipePaths = await recipeHandler.LocateCustomRecipePaths(webAppWithDockerCsproj, solutionDirectoryPath);

            // ASSERT
            File.Exists(Path.Combine(webAppWithDockerFilePath, "aws-deployments.json")).ShouldBeTrue();
            customRecipePaths.Count.ShouldEqual(2, $"Custom recipes found: {Environment.NewLine} {string.Join(Environment.NewLine, customRecipePaths)}");
            customRecipePaths.ShouldContain(Path.Combine(tempDirectoryPath, "MyCdkApp1"));
            customRecipePaths.ShouldContain(Path.Combine(tempDirectoryPath, "MyCdkApp1"));
        }

        [Fact]
        public async Task LocateCustomRecipePathsWithoutManifestFile()
        {
            var tempDirectoryPath = new TestAppManager().GetProjectPath(string.Empty);
            var webAppWithDockerFilePath = Path.Combine(tempDirectoryPath, "testapps", "WebAppWithDockerFile");
            var webAppNoDockerFilePath = Path.Combine(tempDirectoryPath, "testapps", "WebAppNoDockerFile");
            var webAppWithDockerCsproj = Path.Combine(webAppWithDockerFilePath, "WebAppWithDockerFile.csproj");
            var webAppNoDockerCsproj = Path.Combine(webAppNoDockerFilePath, "WebAppNoDockerFile.csproj");
            var solutionDirectoryPath = tempDirectoryPath;
            var recipeHandler = BuildRecipeHandler();
            await _commandLineWrapper.Run("git init", tempDirectoryPath);

            // ARRANGE - Create 2 CDK deployment projects that contain the custom recipe snapshot
            await Utilities.CreateCDKDeploymentProject(webAppWithDockerFilePath, Path.Combine(tempDirectoryPath, "MyCdkApp1"));
            await Utilities.CreateCDKDeploymentProject(webAppWithDockerFilePath, Path.Combine(tempDirectoryPath, "MyCdkApp2"));

            // ACT - Fetch custom recipes corresponding to a different target application (under source control) without a deployment-manifest file.
            var customRecipePaths = await recipeHandler.LocateCustomRecipePaths(webAppNoDockerCsproj, solutionDirectoryPath);

            // ASSERT
            File.Exists(Path.Combine(webAppNoDockerFilePath, "aws-deployments.json")).ShouldBeFalse();
            customRecipePaths.Count.ShouldEqual(2, $"Custom recipes found: {Environment.NewLine} {string.Join(Environment.NewLine, customRecipePaths)}");
            customRecipePaths.ShouldContain(Path.Combine(tempDirectoryPath, "MyCdkApp1"));
            customRecipePaths.ShouldContain(Path.Combine(tempDirectoryPath, "MyCdkApp1"));
        }

        private IRecipeHandler BuildRecipeHandler()
        {
            var directoryManager = new DirectoryManager();
            var fileManager = new FileManager();
            var deploymentManifestEngine = new DeploymentManifestEngine(directoryManager, fileManager);
            var serviceProvider = new Mock<IServiceProvider>();
            var validatorFactory = new ValidatorFactory(serviceProvider.Object);
            var optionSettingHandler = new OptionSettingHandler(validatorFactory);
            return new RecipeHandler(deploymentManifestEngine, _inMemoryInteractiveService, directoryManager, fileManager, optionSettingHandler, validatorFactory);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                _inMemoryInteractiveService.ReadStdOutStartToEnd();
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        ~CustomRecipeLocatorTests() => Dispose(false);
    }
}