using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Threading;

namespace Adaptation._Tests.Shared;

public class UnitTesting
{

    protected readonly bool _HasWaitForProperty;
    protected readonly IsEnvironment _IsEnvironment;
    protected readonly string _TestContextPropertiesAsJson;

    public IsEnvironment IsEnvironment => _IsEnvironment;
    public bool HasWaitForProperty => _HasWaitForProperty;
    public string TestContextPropertiesAsJson => _TestContextPropertiesAsJson;

    public UnitTesting(TestContext testContext, Type declaringType)
    {
        if (testContext is null || declaringType is null)
            _IsEnvironment = null;
        else
        {
            string waitFor = "\"WaitFor\":";
            string projectDirectory = GetProjectDirectory(testContext);
            if (string.IsNullOrEmpty(projectDirectory))
                _IsEnvironment = null;
            else
            {
                _TestContextPropertiesAsJson = JsonSerializer.Serialize(testContext.Properties, new JsonSerializerOptions { WriteIndented = true });
                _HasWaitForProperty = _TestContextPropertiesAsJson.Contains(waitFor);
                string vsCodeDirectory = Path.Combine(projectDirectory, ".vscode");
                if (!Directory.Exists(vsCodeDirectory))
                    _ = Directory.CreateDirectory(vsCodeDirectory);
                string launchText = GetLaunchText();
                File.WriteAllText(Path.Combine(vsCodeDirectory, "launch.json"), launchText);
                if (_HasWaitForProperty)
                {
                    for (int i = 0; i < int.MaxValue; i++)
                    {
                        if (!_TestContextPropertiesAsJson.Contains($"{waitFor} \"Debugger.IsAttached\"") || Debugger.IsAttached)
                            break;
                        Thread.Sleep(500);
                    }
                }
                MethodBase methodBase = declaringType.GetMethod(testContext.TestName);
                if (methodBase is not null)
                {
                    TestCategoryAttribute testCategoryAttribute = methodBase.GetCustomAttribute<TestCategoryAttribute>();
                    if (testCategoryAttribute is not null)
                    {
                        foreach (string testCategory in testCategoryAttribute.TestCategories)
                            _IsEnvironment = new IsEnvironment(testCategory);
                    }
                }
                _IsEnvironment ??= new IsEnvironment(processesCount: null, nullASPNetCoreEnvironmentIsDevelopment: Debugger.IsAttached, nullASPNetCoreEnvironmentIsProduction: !Debugger.IsAttached);
            }
        }
    }

    internal static string GetProjectDirectory(TestContext testContext)
    {
        string result;
        string[] checkFiles;
        result = Path.GetDirectoryName(testContext.DeploymentDirectory);
        for (int i = 0; i < int.MaxValue; i++)
        {
            if (string.IsNullOrEmpty(result))
                break;
            checkFiles = Directory.GetFiles(result, "*.Tests.*proj", SearchOption.TopDirectoryOnly);
            if (checkFiles.Any())
                break;
            result = Path.GetDirectoryName(result);
        }
        return result;
    }

    internal static string GetLaunchText()
    {
        StringBuilder result = new();
        _ = result.
            AppendLine("{").
            AppendLine("  \"configurations\": [").
            AppendLine("    {").
            AppendLine("      \"name\": \".NET Core Attach\",").
            AppendLine("      \"type\": \"coreclr\",").
            AppendLine("      \"request\": \"attach\",").
            AppendLine($"      \"processId\": {Environment.ProcessId}").
            AppendLine("    }").
            AppendLine("  ]").
            AppendLine("}");
        return result.ToString();
    }

}