using System.IO;
using System.Text.Json;
using ConeCalorimeter.Models;
using Serilog;

namespace ConeCalorimeter.Services;

public sealed class JsonReportInputPersistenceService : IReportInputPersistenceService
{
    private static readonly JsonSerializerOptions JsonOptions = new()
    {
        WriteIndented = true
    };

    public JsonReportInputPersistenceService()
        : this(Path.Combine(
            Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
            "ConeCalorimeter",
            "report-manual-input.json"))
    {
    }

    public JsonReportInputPersistenceService(string storagePath)
    {
        StoragePath = storagePath;
    }

    public string StoragePath { get; }

    public IReadOnlyDictionary<string, ReportManualEntryFieldState> Load()
    {
        if (!File.Exists(StoragePath))
        {
            return new Dictionary<string, ReportManualEntryFieldState>();
        }

        try
        {
            using var stream = File.OpenRead(StoragePath);
            var state = JsonSerializer.Deserialize<ReportManualEntryState>(stream, JsonOptions);
            return state?.Fields ?? new Dictionary<string, ReportManualEntryFieldState>();
        }
        catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or JsonException)
        {
            Log.Warning(ex, "Report manual input JSON load failed. Path={Path}.", StoragePath);
            return new Dictionary<string, ReportManualEntryFieldState>();
        }
    }

    public void Save(IReadOnlyDictionary<string, ReportManualEntryFieldState> fields)
    {
        var directory = Path.GetDirectoryName(StoragePath);
        if (!string.IsNullOrWhiteSpace(directory))
        {
            Directory.CreateDirectory(directory);
        }

        var state = new ReportManualEntryState
        {
            Fields = fields.ToDictionary(
                pair => pair.Key,
                pair => new ReportManualEntryFieldState
                {
                    Value = pair.Value.Value ?? string.Empty,
                    IsAutoFilled = pair.Value.IsAutoFilled
                })
        };

        var tempPath = $"{StoragePath}.tmp";
        using (var stream = File.Create(tempPath))
        {
            JsonSerializer.Serialize(stream, state, JsonOptions);
        }

        File.Move(tempPath, StoragePath, true);
    }
}
