using Couchbase.Lite;
using WorkTracker.Domain;
using WorkTracker.Services.Storage;

namespace WorkTracker.Services.Settings;

public sealed class CouchbaseLiteAppSettingsService : IAppSettingsService
{
    private const string DefaultSettingsId = "global";

    private readonly Collection appSettingsCollection;

    public CouchbaseLiteAppSettingsService(CouchbaseLiteDatabaseProvider databaseProvider)
    {
        appSettingsCollection = databaseProvider.AppSettings;
    }

    public Task<AppSettingsDocument> GetAsync(CancellationToken cancellationToken = default)
    {
        cancellationToken.ThrowIfCancellationRequested();

        var document = appSettingsCollection.GetDocument(DefaultSettingsId);
        if (document is not null)
        {
            return Task.FromResult(Map(document));
        }

        var defaults = new AppSettingsDocument();
        SaveDocument(defaults);
        return Task.FromResult(defaults);
    }

    public async Task<AppSettingsDocument> SaveAsync(AppSettingsDocument settings, CancellationToken cancellationToken = default)
    {
        cancellationToken.ThrowIfCancellationRequested();

        var existing = await GetAsync(cancellationToken);

        settings.Id = DefaultSettingsId;
        settings.CreatedAtUtc = existing.CreatedAtUtc;
        settings.UpdatedAtUtc = DateTimeOffset.UtcNow;

        SaveDocument(settings);
        return settings;
    }

    private void SaveDocument(AppSettingsDocument settings)
    {
        var document = new MutableDocument(DefaultSettingsId);
        document.SetDouble("standardWorkHoursPerDay", Decimal.ToDouble(settings.StandardWorkHoursPerDay));
        document.SetDouble("lunchBreakHours", Decimal.ToDouble(settings.LunchBreakHours));
        document.SetDouble("hourlyGrossRate", Decimal.ToDouble(settings.HourlyGrossRate));
        document.SetDouble("profitabilityCoefficient", Decimal.ToDouble(settings.ProfitabilityCoefficient));
        document.SetDouble("inpsRate", Decimal.ToDouble(settings.InpsRate));
        document.SetDouble("substituteTaxRate", Decimal.ToDouble(settings.SubstituteTaxRate));
        document.SetString("currency", settings.Currency);
        document.SetString("locale", settings.Locale);
        document.SetString("createdAtUtc", settings.CreatedAtUtc.ToString("O"));
        document.SetString("updatedAtUtc", settings.UpdatedAtUtc.ToString("O"));

        appSettingsCollection.Save(document);
    }

    private static AppSettingsDocument Map(Document document)
    {
        return new AppSettingsDocument
        {
            Id = document.Id,
            StandardWorkHoursPerDay = ReadDecimal(document, "standardWorkHoursPerDay", 8m),
            LunchBreakHours = ReadDecimal(document, "lunchBreakHours", 1m),
            HourlyGrossRate = ReadDecimal(document, "hourlyGrossRate", 17.5m),
            ProfitabilityCoefficient = ReadDecimal(document, "profitabilityCoefficient", 0.67m),
            InpsRate = ReadDecimal(document, "inpsRate", 0.2607m),
            SubstituteTaxRate = ReadDecimal(document, "substituteTaxRate", 0.15m),
            Currency = document.GetString("currency") ?? "EUR",
            Locale = document.GetString("locale") ?? "it-IT",
            CreatedAtUtc = ReadDateTimeOffset(document, "createdAtUtc"),
            UpdatedAtUtc = ReadDateTimeOffset(document, "updatedAtUtc")
        };
    }

    private static decimal ReadDecimal(Document document, string key, decimal defaultValue)
    {
        return document.Contains(key)
            ? Convert.ToDecimal(document.GetDouble(key))
            : defaultValue;
    }

    private static DateTimeOffset ReadDateTimeOffset(Document document, string key)
    {
        var value = document.GetString(key);
        return DateTimeOffset.TryParse(value, out var parsed)
            ? parsed
            : DateTimeOffset.UtcNow;
    }
}