using Microsoft.Extensions.Logging;
using LDBproject.Entities;
using Newtonsoft.Json;
using Npgsql;
using Dapper;

namespace LDBproject.Repositories.Implementations;

public class BookR : IBookRep
{
    private readonly IConnectionString _connectionString;
    private readonly ILogger<BookR> _logger;

    public BookR(IConnectionString connectionString, ILogger<BookR> logger)
    {
        _connectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }

    public Book GetBookByID(int id)
    {
        _logger.LogInformation("< Getting BOOK by id >");
        _logger.LogDebug("Object ID: {id}", id);
        try
        {
            using var connection = new NpgsqlConnection(_connectionString.ConnectionString);
            var querySelect = @"SELECT b.*, GenreMask FROM Books b WHERE b.BookID = @BookID";
            return connection.QueryFirstOrDefault<Book>(querySelect, new { BookID = id });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "< Error while reading :') BOOK by ID >");
            throw;
        }
    }

    public void AddBook(Book book)
    {
        _logger.LogInformation("< New BOOK Added >");
        _logger.LogDebug("Object: {json}", JsonConvert.SerializeObject(book));

        try
        {
            using var connection = new NpgsqlConnection(_connectionString.ConnectionString);
            connection.Open();
            var queryInsert = @"INSERT INTO Books (Title, Author, PublishYear, Status, GenreMask)
                    VALUES (@Title, @Author, @PublishYear, @Status, @GenreMask)";
            connection.Execute(queryInsert, book);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "< Error while adding BOOK >");
            throw;
        }
    }

    public void UpdateBook(Book book)
    {
        _logger.LogInformation("< BOOK Info Updated >");
        _logger.LogDebug("Object: {json}", JsonConvert.SerializeObject(book));

        try
        {
            using var connection = new NpgsqlConnection(_connectionString.ConnectionString);
            connection.Open();
            var queryUpdate = @"UPDATE Books SET Title = @Title, Author = @Author,
                    PublishYear = @PublishYear, Status = @Status, GenreMask = @GenreMask
                    WHERE BookID = @BookID";
            connection.Execute(queryUpdate, book);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "< Error while updating BOOK >");
            throw;
        }
    }

    public void DeleteBook(int id)
    {
        _logger.LogInformation("< Removing BOOK >");
        _logger.LogDebug("Object ID: {id}", id);

        try
        {
            using var connection = new NpgsqlConnection(_connectionString.ConnectionString);
            var queryDelete = @"DELETE FROM Books WHERE BookID = @BookID";
            connection.Execute(queryDelete, new { BookID = id });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "< Error while deleting BOOK >");
            throw;
        }
    }

    public IEnumerable<Book> GetBookList()
    {
        _logger.LogInformation("< Getting all BOOKS >");
        try
        {
            using var connection = new NpgsqlConnection(_connectionString.ConnectionString);
            connection.Open();
            var querySelectAll = @"SELECT b.*, GenreMask FROM Books b";
            var books = connection.Query<Book>(querySelectAll);

            _logger.LogDebug("Aimed objects: {json}", JsonConvert.SerializeObject(books));
            return books;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "< Error while getting BOOKS >");
            throw;
        }
    }
}