using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;

namespace PCL.Core.SourceGenerators;

[Generator(LanguageNames.CSharp)]
public class EnvironmentInteropGenerator : IIncrementalGenerator
{
    public void Initialize(IncrementalGeneratorInitializationContext context)
    {
        var secretProvider = context.CompilationProvider.Select(static (_, _) =>
        {
            // 判断 PCL_WRITE_SECRET 是否存在并遍历转换环境变量
            // 打死也不会用 MSBuild Properties 这种非人类设计出来的垃圾
#pragma warning disable RS1035
            var envs = Environment.GetEnvironmentVariables();
#pragma warning restore RS1035
            var secretPairs = envs.Contains("PCL_WRITE_SECRET") ? (
                from key in (
                    from key in envs.Keys.Cast<string>()
                    where !string.IsNullOrWhiteSpace(key) && key.StartsWith("PCL_") && key != "PCL_WRITE_SECRET"
                    select key
                )
                let value = envs[key]?.ToString()
                where !string.IsNullOrWhiteSpace(value)
                select (key.Substring(4), value)
            ) : [];
            return secretPairs;
        });

        // 注册源代码输出
        context.RegisterSourceOutput(secretProvider, static (spc, secretPairs) => _Execute(spc, secretPairs));
    }

    private static void _Execute(SourceProductionContext context, IEnumerable<(string, string)> secretPairs)
    {
        var sb = new StringBuilder();
        sb.AppendLine("// <auto-generated />");
        sb.AppendLine("// 此文件由 Source Generator 自动生成，请勿手动修改");
        sb.AppendLine();
        sb.AppendLine("#nullable enable");
        sb.AppendLine();
        sb.AppendLine("namespace PCL.Core.Utils.OS;");
        sb.AppendLine();
        sb.AppendLine("partial class EnvironmentInterop");
        sb.AppendLine("{");
        sb.AppendLine("    private static readonly System.Collections.Generic.Dictionary<string, string?> SecretDictionary = new()");
        sb.AppendLine("    {");

        foreach (var (key, value) in secretPairs)
            sb.AppendLine($"        [\"{key}\"] = {_ToVerbatimString(value)},");

        sb.AppendLine("    };");
        sb.AppendLine("}");

        context.AddSource("EnvironmentInterop.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
    }

    private static string _ToVerbatimString(string text)
    {
        return "@\"" + text.Replace("\"", "\"\"") + "\"";
    }
}
