using System.Data;
using FastBlog.Core.Abstractions.Repositories.Blogs;
using FastBlog.Core.Abstractions.Repositories.Files;
using FastBlog.Core.Db;
using FastBlog.Core.Models.Blogs;
using FastBlog.Core.Options;
using FastBlog.Core.Repositories;
using FastBlog.Core.Services;
using FluentMigrator.Runner;
using Microsoft.Data.Sqlite;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace FastBlog.Core;

public static class DependencyInjection
{
    public static IServiceCollection AddCore(this IServiceCollection services, IConfiguration configuration)
    {
        // applicatrion
        services.AddSingleton<BlogService>();
        services.AddSingleton<FileService>();
        
        // options
        services.Configure<FileStoreOptions>(configuration.GetSection("FileStore"));
        
        // infrastructure
        services.AddSingleton<IBlogMetaRepository, BlogMetaRepository>();
        services.AddSingleton<IBlogFileRepository, BlogFileRepository>();
        services.AddSingleton<IFileMetaRepository, FileMetaRepository>();
        services.AddSingleton<IFileRepository, FileRepository>();

        // storage
        var connectionString = configuration.GetConnectionString("Sqlite");
        
        services.AddScoped<IDbConnection>(_ => new SqliteConnection());
        services.AddTransient<SqliteConnection>(_ => new(connectionString));
        services.AddSingleton<SqliteConnectionFactory>(_ => new(configuration));
        
        services.AddFluentMigratorCore()
            .ConfigureRunner(rb =>
                rb.AddSQLite()
                    .WithGlobalConnectionString(connectionString)
                    .ScanIn(typeof(Db.Migrations.Init).Assembly).For.Migrations())
            .AddLogging(lb => lb.AddFluentMigratorConsole());
        
        return services;
    }

    public static async Task MigrateUp(this IServiceProvider provider, IConfiguration configuration)
    {
        await using var scope = provider.CreateAsyncScope();
        var runner = scope.ServiceProvider.GetRequiredService<IMigrationRunner>();
        runner.MigrateUp();

        var blogService = scope.ServiceProvider.GetRequiredService<BlogService>();
        var mainPage = await blogService.Get(null);
        if (mainPage is not null)
            return;
        
        await blogService.Update(new Blog
        {
            Text = BlogDefaultBody,
            Metadata = new BlogMeta
            {
                Title = "Welcome",
                Slug = null,
                CreatedAt = DateTime.UtcNow,
                ModifiedAt = DateTime.UtcNow,
                SourceLocation = "welcome.md",
                ShowDetails = false,
                Visible = false
            }
        });
    }
    
    private const string BlogDefaultBody = """
                                           # Index Page  
                                           ---  
                                           Welcome to your first blog
                                           """;
}