using BlogContracts.BindingModels;
using BlogContracts.SearchModels;
using BlogContracts.StoragesContracts;
using BlogContracts.ViewModels;
using BlogDatabase.Models;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BlogDatabase.Implements
{
    public class MessageStorage : IMessageStorage
    {
        public MessageViewModel? Delete(MessageBindingModel model)
        {
            using var context = new BlogDatabase();
            var element = context.Messages.FirstOrDefault(rec => rec.Id == model.Id);
            if (element != null)
            {
                context.Messages.Remove(element);
                context.SaveChanges();
                return element.GetViewModel;
            }
            return null;
        }

        public MessageViewModel? GetElement(MessageSearchModel model)
        {
            if (!model.Id.HasValue)
            {
                return null;
            }
            using var context = new BlogDatabase();
            return context.Messages
                .Include(x => x.User)
                .Include(x => x.Topic)
                .FirstOrDefault(x => model.Id.HasValue && x.Id == model.Id).GetViewModel;
        }

        public List<MessageViewModel> GetFilteredList(MessageSearchModel model)
        {
            using var context = new BlogDatabase();
            return context.Messages
                .Include(x => x.User)
                .Include(x => x.Topic)
                .Select(x => x.GetViewModel)
                .ToList();
        }

        public List<MessageViewModel> GetFullList()
        {
            using var context = new BlogDatabase();
            return context.Messages
                .Include(x => x.User)
                .Include(x => x.Topic)
                .Select(x => x.GetViewModel)
                .ToList();
        }

        public MessageViewModel? Insert(MessageBindingModel model)
        {
            var newMessage = Message.Create(model);
            if (newMessage == null)
            {
                return null;
            }
            using var context = new BlogDatabase();
            context.Messages.Add(newMessage);
            context.SaveChanges();
            return newMessage.GetViewModel;
        }

        public string TestInsertList(int num, List<UserViewModel> users, List<TopicViewModel> topics)
        {
            Random rnd = new Random();
            using var context = new BlogDatabase();
            for (int i = 0; i < num; ++i)
            {
                var model = new MessageBindingModel
                {
                    Id = 0,
                    Text = "hello",
                    Date = DateTime.SpecifyKind(DateTime.Now, DateTimeKind.Utc),
                    UserId = users[rnd.Next(users.Count)].Id,
                    TopicId = topics[rnd.Next(topics.Count)].Id,
                };
                context.Messages.Add(Message.Create(model));
            }
            Stopwatch stopwatch = new();

            stopwatch.Start();

            context.SaveChanges();

            stopwatch.Stop();
            return stopwatch.ElapsedMilliseconds.ToString();
        }

        public string TestJoinReadList(int num)
        {
            using var context = new BlogDatabase();
            Stopwatch stopwatch = new();

            stopwatch.Start();

            var list = context.Messages
                    .Include(x => x.User)
                    .Include(x => x.Topic)
                    .Join(context.Users,
                        r => r.UserId,
                        c => c.Id,
                        (r, c) => new { Message = r, User = c })
                    .Join(context.Topics,
                        rc => rc.Message.TopicId,
                        car => car.Id,
                        (rc, topic) => new { rc.Message, rc.User, Topic = topic })
                    .Select(rc => new
                    {
                        Message = rc.Message.GetViewModel,
                        User = rc.User.GetViewModel,
                        Topic = rc.Topic.GetViewModel,
                    })
                    .Take(num)
                    .ToList();
            stopwatch.Stop();

            return stopwatch.ElapsedMilliseconds.ToString();
        }

        public string TestReadList(int num)
        {
            using var context = new BlogDatabase();
            Stopwatch stopwatch = new();

            stopwatch.Start();

            List<MessageViewModel> list = context.Messages
                    .Include(x => x.User)
                    .Include(x => x.Topic)
                    .Take(num)
                    .Select(x => x.GetViewModel)
                    .ToList();
            stopwatch.Stop();

            return stopwatch.ElapsedMilliseconds.ToString();
        }

        public MessageViewModel? Update(MessageBindingModel model)
        {
            using var context = new BlogDatabase();
            var component = context.Messages.FirstOrDefault(x => x.Id == model.Id);
            if (component == null)
            {
                return null;
            }
            component.Update(model);
            context.SaveChanges();
            return component.GetViewModel;
        }
    }
}