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

namespace FastBlog.Core.Repositories;

public sealed class FileMetaRepository(SqliteConnectionFactory connectionFactory) : IFileMetaRepository
{
    public async Task<PagedResponse<FileMeta>> List(PagedRequest request)
    {
        const string sql = """
                           select COUNT(*) from Files;
                           select * from Files
                           order by CreatedAt desc
                           limit @Amount offset @Offset;
                           """;
        
        using var connection = connectionFactory.Create();

        await using var multi = await connection.QueryMultipleAsync(sql, request);

        var total = await multi.ReadFirstAsync<long>();
        var result = (await multi.ReadAsync<FileMeta>()).ToArray();

        return PagedResponse<FileMeta>.Create(total, request.Amount, request.Offset, result);
    }

    public async Task<FileMeta?> Get(int id)
    {
        const string sql = """
                           select * from Files
                           where Id = @Id;
                           """;
        
        using var connection = connectionFactory.Create();
        return await connection.QueryFirstOrDefaultAsync<FileMeta>(sql, new { Id = id });
    }

    public async Task<Result<FileMeta, BusinessError>> Add(FileMeta meta)
    {
        const string sql = """
                           insert into Files (SourceLocation, CreatedAt, MimeType)
                           values (@SourceLocation, @CreatedAt, @MimeType)
                           returning *;
                           """;
        
        using var connection = connectionFactory.Create();
        try
        {
            var result = await connection.QueryFirstAsync<FileMeta>(sql, meta);
            return result;
        }
        catch (SqliteException ex)
        {
            if (ex.SqliteErrorCode == 19) // Unique constraint violation
                return new BusinessError("already_exists", "File already exists");

            throw;
        }
    }

    public async Task<bool> Delete(FileMeta meta)
    {
        using var connection = connectionFactory.Create();
        
        const string sql = """
                           delete from Files
                           where Id = @Id;
                           """;
        
        var result = await connection.ExecuteAsync(sql, meta);
        return result > 0;
    }
}