using Dapper;
using FastBlog.Core.Abstractions.Repositories.Users;
using FastBlog.Core.Db;
using FastBlog.Core.Models;
using FastBlog.Core.Models.Users;

namespace FastBlog.Core.Repositories;

public sealed class UserRepository(SqliteConnectionFactory connectionFactory) : IUserRepository
{
    public async Task<User?> Get(int id)
    {
        const string sql = "select * from Users where id = @id";
        using var connection = connectionFactory.Create();
        return await connection.QueryFirstOrDefaultAsync<User>(sql, new { id });
    }

    public async Task<UserPassword?> GetWithPassword(int id)
    {
        const string sql = "select * from Users where id = @id and deleted is false";
        using var connection = connectionFactory.Create();
        return await connection.QueryFirstOrDefaultAsync<UserPassword>(sql, new { id });
    }

    public async Task<UserPassword?> GetByName(string username)
    {
        const string sql = "select * from Users where username = @username";
        using var connection = connectionFactory.Create();
        return await connection.QueryFirstOrDefaultAsync<UserPassword>(sql, new { username });
    }

    public async Task<bool> SetPassword(int id, string newPassword)
    {
        const string sql = "update Users set passwordHash = @newPassword where id = @id and deleted = 0";
        using var connection = connectionFactory.Create();
        return await connection.ExecuteAsync(sql, new { id, newPassword }) > 0;
    }

    public async Task<PagedResponse<User>> GetUsers(PagedRequest pagedRequest)
    {
        const string sql = """
                           select COUNT(*) from Users;
                           select * from Users
                           where deleted = 0
                           limit @Amount offset @Offset;
                           """;
        using var connection = connectionFactory.Create();
        await using var multi = await connection.QueryMultipleAsync(sql, pagedRequest);
        var total = await multi.ReadFirstAsync<int>();
        var result = (await multi.ReadAsync<User>()).ToArray();

        return PagedResponse<User>.Create(total, total, pagedRequest.Offset, result);
    }

    public async Task<User> CreateUser(NewUser newUser)
    {
        const string sql = "insert into Users (username, passwordHash) values (@Username, @Password) returning *";
        using var connection = connectionFactory.Create();
        return await connection.QueryFirstAsync<User>(sql, newUser);
    }

    public async Task<bool> DeleteUser(int userId)
    {
        const string sql = "update Users set deleted = true where id = @userId and deleted = 0";
        using var connection = connectionFactory.Create();
        return await connection.ExecuteAsync(sql, new { userId }) > 0;
    }
}