using System.Globalization;
using CsvHelper;

namespace Inspectron.Statistics;

public class LockedCsvStatistics : IStatistics
{
    private readonly string _filePath;
    private readonly string _lockFilePath;
    private readonly string[] _headers;

    public LockedCsvStatistics(string filePath, string[] headers)
    {
        _filePath = filePath;
        _lockFilePath = filePath + ".lock";
        _headers = headers;

        var directoryPath = Path.GetDirectoryName(filePath);
        if (directoryPath != null && !Directory.Exists(directoryPath))
        {
            Directory.CreateDirectory(directoryPath);
        }
    }

    public void WriteLine(StatisticsRecord record)
    {
        AcquireLock();

        try
        {
            bool writeHeaders = !File.Exists(_filePath) || new FileInfo(_filePath).Length == 0;

            using var fileStream = new FileStream(_filePath, FileMode.Append, FileAccess.Write, FileShare.None);
            using var streamWriter = new StreamWriter(fileStream);
            using var csvWriter = new CsvWriter(streamWriter, CultureInfo.InvariantCulture);

            if (writeHeaders)
            {
                foreach (var header in _headers)
                {
                    csvWriter.WriteField(header);
                }
                csvWriter.NextRecord();
                csvWriter.Flush();
            }

            foreach (var value in record.Values)
            {
                csvWriter.WriteField(value);
            }
            csvWriter.NextRecord();
            csvWriter.Flush();
        }
        finally
        {
            ReleaseLock();
        }
    }

    public void Dispose()
    {
        // No resources to dispose
    }

    private void AcquireLock()
    {
        while (true)
        {
            try
            {
                using (File.Open(_lockFilePath, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None))
                {
                    // Lock acquired
                    break;
                }
            }
            catch (IOException)
            {
                // Lock file already exists, wait and retry
                Thread.Sleep(10);
            }
        }
    }

    private void ReleaseLock()
    {
        if (File.Exists(_lockFilePath))
        {
            File.Delete(_lockFilePath);
        }
    }
}
