using Microsoft.Extensions.Logging;
using SharpChat.Configuration;
using SharpChat.Messages;
using SharpChat.Storage;
using System.Data.SQLite;
using ZLogger;
using NativeSQLiteConnection = System.Data.SQLite.SQLiteConnection;

namespace SharpChat.SQLite;

public class SQLiteStorage(ILogger logger, string connString) : StorageBackend, IDisposable {
    public const string MEMORY = "file::memory:?cache=shared";
    public const string DEFAULT = "sharpchat.db";

    public SQLiteConnection Connection { get; } = new SQLiteConnection(new NativeSQLiteConnection(connString).OpenAndReturn());

    public MessageStorage CreateMessageStorage() {
        return new SQLiteMessageStorage(logger, Connection);
    }

    public async Task UpgradeStorage() {
        logger.ZLogInformation($"Upgrading storage...");
        await new SQLiteMigrations(logger, Connection).RunMigrations();
    }

    public static string BuildConnectionString(Config config, bool journalling = true) {
        return BuildConnectionString(
            config.ReadValue("path", DEFAULT)!,
            config.ReadValue("pass"),
            config.ReadValue("journal", journalling)
        );
    }

    public static string BuildConnectionString(string path, string? password, bool journalling = true) {
        return new SQLiteConnectionStringBuilder {
            DataSource = string.IsNullOrWhiteSpace(path) ? MEMORY : path,
            DateTimeFormat = SQLiteDateFormats.ISO8601,
            DateTimeKind = DateTimeKind.Utc,
            FailIfMissing = false,
            ForeignKeys = true,
            JournalMode = journalling ? SQLiteJournalModeEnum.Wal : SQLiteJournalModeEnum.Off,
            LegacyFormat = false,
            Password = string.IsNullOrWhiteSpace(password) ? null : password,
            ReadOnly = false,
            UseUTF16Encoding = false,
        }.ToString();
    }

    private bool disposed = false;

    ~SQLiteStorage() {
        DoDispose();
    }

    public void Dispose() {
        DoDispose();
        GC.SuppressFinalize(this);
    }

    private void DoDispose() {
        if(disposed)
            return;
        disposed = true;
        Connection.Dispose();
    }
}