using ProjectLibrary.Entities;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Npgsql;
using Dapper;
using System.Collections.Generic;
using ProjectLibrary.Repositories;
using System.Transactions;
using System.Data.Common;
using ProjectLibrary.Entites;
using ProjectLibrary.Repositores;
using Unity;

namespace ProjectLibrary.Repositories.Implementations
{
    public class OrderRepository : IOrderRepository
    {
        private readonly IConnectionString _connectionString;
        private readonly ILogger<OrderRepository> _logger;

        public OrderRepository(IConnectionString connectionString, ILogger<OrderRepository> logger)
        {
            _connectionString = connectionString;
            _logger = logger;
        }

        // Добавление нового заказа
        public void CreateOrder(Orders order)
        {
            _logger.LogInformation("Добавление нового заказа");
            _logger.LogDebug("Заказ: {json}", JsonConvert.SerializeObject(order));
            try
            {
                using var connection = new NpgsqlConnection(_connectionString.ConnectionString);
                connection.Open();
                using var transaction = connection.BeginTransaction();

                // Вставляем сам заказ в таблицу Orders
                var queryInsertOrder = @"
                    INSERT INTO Orders (OrderDate, ReturnDate, ReaderID) 
                    VALUES (@OrderDate, @ReturnDate, @ReaderID);
                    SELECT MAX(Id) FROM Orders"; // Возвращаем ID вставленного заказа
                var orderId = connection.QueryFirst<int>(queryInsertOrder, order, transaction);

                // Вставляем ассоциации книг с заказом в таблицу Book_Orders
                foreach (var bookId in order.BookOrders)  // Предполагается, что Order.BookOrders содержит список ID книг
                {
                    var queryInsertBookOrder = @"
                        INSERT INTO Book_Orders (BookID, OrderID, Count) 
                        VALUES (@BookID, @OrderID, @Count)";
                    connection.Execute(queryInsertBookOrder, new { bookId.BookID, orderId, bookId.Count }, transaction);
                }
                transaction.Commit();
                _logger.LogInformation("Заказ успешно добавлен с ID={OrderId}", orderId);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Ошибка при добавлении заказа");
                throw;
            }
        }

        // Удаление заказа
        public void DeleteOrder(int id)
        {
            _logger.LogInformation("Удаление объекта");
            _logger.LogDebug("Объект: {id}", id);
            try
            {
                using var connection = new NpgsqlConnection(_connectionString.ConnectionString);
                connection.Open();
                using var transaction = connection.BeginTransaction();
                var querySubDelete = @"
                            DELETE FROM Book_Orders
                            WHERE OrderId=@id";
                connection.Execute(querySubDelete, new { id }, transaction);
                var queryDelete = @"
                            DELETE FROM Orders
                            WHERE Id=@id";
                connection.Execute(queryDelete, new { id }, transaction);
                transaction.Commit();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Ошибка при удалении объекта");
                throw;
            }
        }

        // Получение заказа по ID
        public Orders ReadOrderById(int id)
        {
            _logger.LogInformation("Получение заказа по ID={id}", id);
            try
            {
                using var connection = new NpgsqlConnection(_connectionString.ConnectionString);
                var querySelectOrder = "SELECT * FROM Orders WHERE ID = @id";
                var order = connection.QueryFirstOrDefault<Orders>(querySelectOrder, new { id });
                _logger.LogDebug("Найден заказ: {json}", JsonConvert.SerializeObject(order));

                return order;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Ошибка при получении заказа с ID={id}", id);
                throw;
            }
        }

        // Получение всех заказов
        public IEnumerable<Orders> ReadOrders(DateTime? StartDate = null, DateTime? EndDate = null)
        {
            _logger.LogInformation("Получение всех объектов");
            try
            {
                using var connection = new NpgsqlConnection(_connectionString.ConnectionString);
                var builder = new QueryBuilder();
                if(StartDate.HasValue)
                {
                    builder.AddCollerction("ord.OrderDate >= @StartDate");
                }
                /*if (EndDate.HasValue)
                {
                    builder.AddCollerction("ord.ReturnDate < @EndDate");
                }*/
                var querySelect = $@"SELECT ord.*,re.name as ReaderName,
                                    bk.Name as BookName,
                                    Obo.bookid as bookid,
                                    Obo.Orderid, obo.count 
                                    FROM Orders ord
                                    INNER JOIN Book_Orders Obo ON Obo.orderId = ord.Id
                                    Inner join book bk on bk.ID = obo.Bookid
                                    inner join reader re on re.id = ord.readerid
                                    {builder.Build()}";
                var OrderBookDict = new Dictionary<int, List<Book_Orders>>();

                var order = connection
                    .Query<Orders, Book_Orders, Orders>(querySelect, (orders, books_orders) =>
                    {
                        if (!OrderBookDict.TryGetValue(orders.Id, out var Book_Orders))
                        {
                            Book_Orders = [];
                            OrderBookDict.Add(orders.Id, Book_Orders);
                        }
                        books_orders.BookName = orders.BookName;
                        
                        Book_Orders.Add(books_orders);
                        return orders;
                    },
                    splitOn: "bookid", param: new { StartDate, EndDate });

                _logger.LogDebug("Получ енные объекты: {json}", JsonConvert.SerializeObject(order));
                return OrderBookDict.Select(x =>
                {
                    var or = order.First(y => y.Id == x.Key);
                    or.SetOrdersOfBooks(x.Value);
                    return or;
                }).ToArray();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Ошибка при чтении объектов");
                throw;
            }
        }
    }
}