using System.Reactive.Linq;
using InnovEnergy.App.Backend.DataTypes;
using InnovEnergy.App.Backend.DataTypes.Methods;
using InnovEnergy.App.Backend.Relations;
using InnovEnergy.Lib.Utils;
using SQLite;



namespace InnovEnergy.App.Backend.Database;


public static partial class Db 
{
    internal const String DbPath = "./db.sqlite";

    private static SQLiteConnection Connection { get; } = new SQLiteConnection(DbPath);

    public static TableQuery<Session>           Sessions          => Connection.Table<Session>();
    public static TableQuery<Folder>            Folders           => Connection.Table<Folder>();
    public static TableQuery<Installation>      Installations     => Connection.Table<Installation>();
    public static TableQuery<User>              Users             => Connection.Table<User>();
    public static TableQuery<FolderAccess>       FolderAccess       => Connection.Table<FolderAccess>();
    public static TableQuery<InstallationAccess> InstallationAccess => Connection.Table<InstallationAccess>();


    static Db()
    {
        // on startup create/migrate tables

        Connection.RunInTransaction(() =>
        {
            Connection.CreateTable<User>();
            Connection.CreateTable<Installation>();
            Connection.CreateTable<Folder>();
            Connection.CreateTable<FolderAccess>();
            Connection.CreateTable<InstallationAccess>();
            Connection.CreateTable<Session>();
        });


    

        Observable.Interval(TimeSpan.FromDays(0.5))
                  .StartWith(0) // Do it right away (on startup)
                  .SelectMany(Cleanup)
                  .Subscribe();         // and then daily
    }

    
    
    private static Boolean RunTransaction(Func<Boolean> func)
    {
        var savepoint = Connection.SaveTransactionPoint();
        var success = false;
        
        try
        {
            success = func();
        }
        finally
        {
            if (success)
                Connection.Release(savepoint);
            else
                Connection.RollbackTo(savepoint);
        }

        return success;
    }


    private static async Task<Boolean> Cleanup(Int64 _)
    {
        await UpdateS3Urls();
        DeleteStaleSessions();
        return true;
    }

    private static void DeleteStaleSessions()
    {
        var deadline = DateTime.Now - Session.MaxAge;
        Sessions.Delete(s => s.LastSeen < deadline);
    }

    private static Task UpdateS3Urls()
    {
        var renewTasks = Installations.Select(i => i.RenewS3BucketUrl()).ToArray();
        return Task.WhenAll(renewTasks);
    }
}