using Dapper;
using FastBlog.Core.Abstractions.Repositories.Blogs;
using FastBlog.Core.Db;
using FastBlog.Core.Models;
using FastBlog.Core.Models.Blogs;
using Microsoft.Data.Sqlite;

namespace FastBlog.Core.Repositories;

public sealed class BlogMetaRepository(SqliteConnectionFactory connectionFactory) : IBlogMetaRepository
{
    public async Task<BlogMeta?> Get(string? slug)
    {
        using var connection = connectionFactory.Create();

        const string sqlNull = """
                               select * from Blogs
                               where slug is null
                               and CreatedAt <= datetime('now')
                               """;

        const string sql = """
                           select * from Blogs
                           where (slug = @slug or id = cast(@slug as integer))
                           and CreatedAt <= datetime('now')
                           """;

        if (slug is null)
            return await connection.QueryFirstOrDefaultAsync<BlogMeta>(sqlNull);
        return await connection.QueryFirstOrDefaultAsync<BlogMeta>(sql, new { slug });
    }

    public async Task<BlogMeta?> GetForEdit(int id)
    {
        using var connection = connectionFactory.Create();

        const string sql = """
                           select * from Blogs
                           where id = @id
                           """;

        return await connection.QueryFirstOrDefaultAsync<BlogMeta>(sql, new { id });
    }

    public async Task<bool> Delete(int id)
    {
        const string sql = """
                           delete from Blogs
                           where id = @id
                           """;
        
        using var connection = connectionFactory.Create();
        
        return await connection.ExecuteAsync(sql, new { id }) > 0;
    }

    public async Task<Result<BlogMeta, BusinessError>> Add(BlogMeta meta)
    {
        using var connection = connectionFactory.Create();

        const string sql = """
                           insert into Blogs (Title, SourceLocation, Slug, ShowDetails, ImageUrl, CreatedAt, ModifiedAt, Signature, FullWidth, Visible)
                           values (@Title, @SourceLocation, @Slug, @ShowDetails, @ImageUrl, @CreatedAt, @ModifiedAt, @Signature, @FullWidth, @Visible)
                           returning *
                           """;
        try
        {
            return await connection.QueryFirstAsync<BlogMeta>(sql, meta);
        }
        catch (SqliteException ex)
        {
            if (ex.SqliteErrorCode == 19) // Unique constraint violation
                return new BusinessError("already_exists","Slug already exists");

            throw;
        }
    }

    public async Task<Result<BlogMeta, BusinessError>> Update(BlogMeta meta)
    {
        using var connection = connectionFactory.Create();

        const string sql = """
                           update Blogs
                           set Title = @Title, SourceLocation = @SourceLocation, Slug = @Slug, ShowDetails = @ShowDetails, ImageUrl = @ImageUrl, CreatedAt = @CreatedAt, ModifiedAt = @ModifiedAt, Signature = @Signature, FullWidth = @FullWidth, Visible = @Visible
                           where id = @Id
                           returning *
                           """;

        try
        {
            return await connection.QueryFirstAsync<BlogMeta>(sql, meta);
        }
        catch (SqliteException ex)
        {
            if (ex.SqliteErrorCode == 19) // Unique constraint violation
                return new BusinessError("already_exists","Slug already exists");
            throw;
        }
    }
}