namespace Logger;

/// <summary>
/// Logger implementation that writes to file with rotation support
/// </summary>
public class FileLogger : ILogger
{
    private readonly FileLoggerOptions _options;
    private readonly object _lockObject = new();

    public FileLogger(FileLoggerOptions options)
    {
        _options = options ?? throw new ArgumentNullException(nameof(options));
        EnsureLogDirectory();
    }

    public void Trace(string message) => Log(LogLevel.Trace, message);
    public void Debug(string message) => Log(LogLevel.Debug, message);
    public void Info(string message) => Log(LogLevel.Info, message);
    public void Warning(string message) => Log(LogLevel.Warning, message);
    public void Error(string message) => Log(LogLevel.Error, message);
    public void Fatal(string message) => Log(LogLevel.Fatal, message);

    public void Log(LogLevel level, string message)
    {
        if (level < _options.MinimumLevel)
            return;

        var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
        var formattedMessage = $"[{timestamp}] [{level}] {message}";

        lock (_lockObject)
        {
            try
            {
                RotateFileIfNeeded();
                var logPath = GetLogFilePath();
                File.AppendAllText(logPath, formattedMessage + Environment.NewLine);
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine($"Error writing to log file: {ex.Message}");
            }
        }
    }

    private void EnsureLogDirectory()
    {
        try
        {
            if (!Directory.Exists(_options.LogDirectory))
            {
                Directory.CreateDirectory(_options.LogDirectory);
            }
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine($"Error creating log directory: {ex.Message}");
        }
    }

    private void RotateFileIfNeeded()
    {
        var logPath = GetLogFilePath();

        if (!File.Exists(logPath))
            return;

        var fileInfo = new FileInfo(logPath);
        if (fileInfo.Length >= _options.MaxFileSizeBytes)
        {
            ArchiveCurrentLog(logPath);
        }
    }

    private void ArchiveCurrentLog(string currentLogPath)
    {
        try
        {
            var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(_options.FileName);
            var fileExtension = Path.GetExtension(_options.FileName);
            var timestamp = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
            var archivePath = Path.Combine(_options.LogDirectory, 
                $"{fileNameWithoutExtension}_{timestamp}{fileExtension}");

            File.Move(currentLogPath, archivePath, overwrite: true);

            CleanupOldBackups();
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine($"Error archiving log file: {ex.Message}");
        }
    }

    private void CleanupOldBackups()
    {
        try
        {
            var directory = new DirectoryInfo(_options.LogDirectory);
            var pattern = $"{Path.GetFileNameWithoutExtension(_options.FileName)}_*";
            
            var backupFiles = directory.GetFiles(pattern)
                .OrderByDescending(f => f.CreationTime)
                .Skip(_options.MaxBackupFiles)
                .ToList();

            foreach (var file in backupFiles)
            {
                file.Delete();
            }
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine($"Error cleaning up old backup files: {ex.Message}");
        }
    }

    private string GetLogFilePath()
    {
        return Path.Combine(_options.LogDirectory, _options.FileName);
    }
}
