// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using CommonWriterType = System.Action<string, string, System.Collections.Generic.IEnumerable<string>>;

#nullable disable

namespace Microsoft.Build.Shared.Debugging
{
    /// <summary>
    ///     A collection of useful writers
    /// </summary>
    internal static class PrintLineDebuggerWriters
    {
        public sealed class IdBasedFilesWriter
        {
            private string LogFileRoot { get; }

            public CommonWriterType Writer => (id, callsite, args) =>
            {
                try
                {
                    var file = Path.Combine(LogFileRoot, string.IsNullOrEmpty(id) ? "NoId" : id) + ".csv";
                    File.AppendAllText(file, CsvFormat(string.Empty, callsite, args));
                }
                catch (Exception e)
                {
                    var errorFile = Path.Combine(LogFileRoot, $"LoggingException_{Guid.NewGuid()}");
                    File.AppendAllText(errorFile, $"{SimpleFormat(id, callsite, args)}\n{e.Message}\n{e.StackTrace}");
                }
            };

            public IdBasedFilesWriter(string logFileRoot)
            {
                this.LogFileRoot = logFileRoot;
                Directory.CreateDirectory(logFileRoot);
            }

            public static IdBasedFilesWriter FromArtifactLogDirectory()
            {
                return new IdBasedFilesWriter(ArtifactsLogDirectory);
            }
        }

        public sealed class CompositeWriter
        {
            private IEnumerable<CommonWriterType> Writers { get; }

            public CommonWriterType Writer => (id, callsite, args) =>
            {
                var argsArray = args as string[] ?? args.ToArray();

                foreach (var writer in Writers)
                {
                    writer(id, callsite, argsArray);
                }
            };

            public CompositeWriter(IEnumerable<CommonWriterType> writers)
            {
                Writers = writers;
            }
        }

        public static CommonWriterType StdOutWriter = (id, callsite, args) => Console.WriteLine(SimpleFormat(id, callsite, args));

        private static readonly Lazy<string> _artifactsLogs = new Lazy<string>(
            () =>
            {
                var executingAssembly = FileUtilities.ExecutingAssemblyPath;

                var binPart = $"bin";

                var logIndex = executingAssembly.IndexOf(binPart, StringComparison.Ordinal);

                var artifactsPart = executingAssembly.Substring(0, logIndex);
                return logIndex < 0
                    ? null
                    : Path.Combine(artifactsPart, "log", "Debug");
            });

        public static string ArtifactsLogDirectory => _artifactsLogs.Value;

        public static string SimpleFormat(string id, string callsite, IEnumerable<string> args)
        {
            return $"\n{(id == null ? string.Empty : id + ": ")}{callsite}:{string.Join(";", args)}";
        }

        public static string CsvFormat(string id, string callsite, IEnumerable<string> args)
        {
            var joinedArgs = $"{EscapeCommas(callsite)},{string.Join(",", args.Select(arg => EscapeCommas(arg)))}\n";

            return string.IsNullOrEmpty(id)
                ? joinedArgs
                : $"{EscapeCommas(id)},{joinedArgs}";

            string EscapeCommas(string s)
            {
                return s.Replace(",", ";");
            }
        }
    }
}
