using EonaCat.Json;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

// This file is part of the EonaCat project(s) which is released under the Apache License.
// See the LICENSE file or go to https://EonaCat.com/License for full license details.

namespace EonaCat.Logger.EonaCatCoreLogger
{
    public class JsonFileLogger : ILogger
    {
        private readonly string _categoryName;
        private readonly JsonFileLoggerOptions _options;
        private readonly string _filePath;
        private readonly LoggerScopedContext _context = new();
        public bool IncludeCorrelationId { get; set; }
        public event EventHandler<Exception> OnException;

        public JsonFileLogger(string categoryName, JsonFileLoggerOptions options)
        {
            _categoryName = categoryName;
            _options = options;
            _filePath = Path.Combine(_options.LogDirectory, _options.FileName);
            Directory.CreateDirectory(_options.LogDirectory);
            IncludeCorrelationId = options.IncludeCorrelationId;
        }

        public void SetContext(string key, string value) => _context.Set(key, value);
        public void ClearContext() => _context.Clear();
        public string GetContext(string key) => _context.Get(key);

        public IDisposable BeginScope<TState>(TState state) => null;
        public bool IsEnabled(LogLevel logLevel) => _options.IsEnabled;

        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state,
            Exception exception, Func<TState, Exception, string> formatter)
        {
            if (!IsEnabled(logLevel))
            {
                return;
            }

            string message = formatter(state, exception);
            if (IncludeCorrelationId)
            {
                var correlationId = _context.Get("CorrelationId") ?? Guid.NewGuid().ToString();
                _context.Set("CorrelationId", correlationId);
            }

            var logObject = new Dictionary<string, object>
            {
                { "timestamp", DateTime.UtcNow },
                { "level", logLevel.ToString() },
                { "category", _categoryName },
                { "message", message },
                { "exception", exception?.ToString() },
                { "eventId", eventId.Id }
            };

            var contextData = _context.GetAll();
            if (contextData.Count > 0)
            {
                logObject["context"] = contextData;
            }

            try
            {
                string json = JsonHelper.ToJson(logObject);
                File.AppendAllText(_filePath, json + Environment.NewLine, Encoding.UTF8);
            }
            catch (Exception e)
            {
                OnException?.Invoke(this, e);
            }
        }
    }
}
