using System.Text;



namespace NexusInstaller.Services;



internal sealed class InstallerLogService

{

    private static readonly Lazy<InstallerLogService> Lazy = new(() => new InstallerLogService());



    public static InstallerLogService Instance => Lazy.Value;



    private readonly object _lock = new();

    private readonly StringBuilder _buffer = new();

    private readonly string _logPath;



    private InstallerLogService()

    {

        var logDir = Path.Combine(

            Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),

            "NinjaNexus",

            "installer");

        Directory.CreateDirectory(logDir);

        _logPath = Path.Combine(logDir, "setup-log.txt");

    }



    public event Action<string>? LineAdded;



    public string FullText

    {

        get

        {

            lock (_lock)

            {

                return _buffer.ToString();

            }

        }

    }



    public void Info(string message) => Write("INFO", message);



    public void Warn(string message) => Write("WARN", message);



    public void Error(string message) => Write("ERROR", message);



    private void Write(string level, string message)

    {

        var sanitized = Sanitize(message);

        var line = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [{level}] {sanitized}";



        lock (_lock)

        {

            _buffer.AppendLine(line);

            try

            {

                File.AppendAllText(_logPath, line + Environment.NewLine);

            }

            catch

            {

                // best-effort file logging

            }

        }



        LineAdded?.Invoke(line);

    }



    private static string Sanitize(string message)

    {

        if (string.IsNullOrEmpty(message))

        {

            return string.Empty;

        }



        // Strip anything that looks like a credential or token — no secrets in log.

        var result = message;

        foreach (var marker in new[] { "password", "token", "secret", "apikey", "api_key" })

        {

            var idx = result.IndexOf(marker, StringComparison.OrdinalIgnoreCase);

            if (idx >= 0)

            {

                result = result[..idx] + "[redacted]";

            }

        }



        return result;

    }

}


