using System.Collections.Generic;
using System.IO;
using System.Linq;
using Semmle.Util;
using Semmle.Util.Logging;

namespace Semmle.Extraction.CSharp.DependencyFetching
{
    internal class ImplicitUsingsGenerator : SourceGeneratorBase
    {
        private readonly FileContent fileContent;

        public ImplicitUsingsGenerator(FileContent fileContent, ILogger logger, TemporaryDirectory tempWorkingDirectory)
            : base(logger, tempWorkingDirectory)
        {
            this.fileContent = fileContent;
        }

        protected override bool IsEnabled() => true;

        protected override IEnumerable<string> Run()
        {
            var usings = new HashSet<string>();
            if (!fileContent.UseImplicitUsings)
            {
                logger.LogDebug("Skipping implicit usings generation");
                return [];
            }

            // Hardcoded values from https://learn.microsoft.com/en-us/dotnet/core/project-sdk/overview#implicit-using-directives
            usings.UnionWith([ "System", "System.Collections.Generic", "System.IO", "System.Linq", "System.Net.Http", "System.Threading",
                "System.Threading.Tasks" ]);

            if (fileContent.UseAspNetCoreDlls)
            {
                usings.UnionWith([ "System.Net.Http.Json", "Microsoft.AspNetCore.Builder", "Microsoft.AspNetCore.Hosting",
                    "Microsoft.AspNetCore.Http", "Microsoft.AspNetCore.Routing", "Microsoft.Extensions.Configuration",
                    "Microsoft.Extensions.DependencyInjection", "Microsoft.Extensions.Hosting", "Microsoft.Extensions.Logging" ]);
            }

            if (fileContent.UseWindowsForms)
            {
                usings.UnionWith(["System.Drawing", "System.Windows.Forms"]);
            }

            usings.UnionWith(fileContent.CustomImplicitUsings);

            logger.LogInfo($"Generating source file for implicit usings. Namespaces: {string.Join(", ", usings.OrderBy(u => u))}");

            if (usings.Count > 0)
            {
                var tempDir = GetTemporaryWorkingDirectory("implicitUsings");
                var path = Path.Join(tempDir, "GlobalUsings.g.cs");
                using (var writer = new StreamWriter(path))
                {
                    writer.WriteLine("// <auto-generated/>");
                    writer.WriteLine("");

                    foreach (var u in usings.OrderBy(u => u))
                    {
                        writer.WriteLine($"global using global::{u};");
                    }
                }

                return [path];
            }

            return [];
        }
    }
}
