using Newtonsoft.Json;
using SvetoforVKBot.Models.Updates;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.SqlClient;
using System.Security.Cryptography;
using VkNet;
using VkNet.Enums.SafetyEnums;
using VkNet.Model.Keyboard;
using VkNet.Model.RequestParams;
using VkNet.Utils;
using VkNet.Model.Template;
using VkNet.Model.Template.Carousel;
using System.Linq;

namespace SvetoforVKBot.Models.Commands.LK.Menu
{
    public class ShowPersonalMenuCarusel
    {
        private const string PHOTOIDNEXT = "-194717824_457239273_446146426236760985";
        //{"id": 457239273, "owner_id": -194717824, "access_key": "446146426236760985"}
        public void Execute(RootObject update, VkApi client, SvetoforVKBot.Data.SvetoforVKBotEntities db, int curCategory, int curProduct, int curWay, double curDayKkal)
        //curCategory - id Categories, curProduct - порядковый номер в массиве продуктов, curWay - для showProductCarusel направление навигации
        {
            MessagesSendParams @params = new MessagesSendParams();
            var chatId = update.@object.message.from_id;
            int i = 0;
            int prevCatalog = 0, nextCatalog = 0;
            int naviState = 0;
            double sum = 0;
            string desc = "";
            int curDay = (int)DateTime.Now.DayOfWeek;
            if (curDay == 0) curDay = 7;

            List<CategoriesDostavka> categories = new List<CategoriesDostavka>();
            List<ProductsDostavka> products = new List<ProductsDostavka>();
            List<ProductsDostavka> allProducts = new List<ProductsDostavka>();
            List<ProductsDostavka> randomFood = new List<ProductsDostavka>();
            //List<ProductsDostavka> personalProducts = new List<ProductsDostavka>();
            var row = new List<MessageKeyboardButton>();
            var listButtons = new List<ReadOnlyCollection<MessageKeyboardButton>>();
            TemplateBuilder templateBuilder = new TemplateBuilder();
            CarouselElementAction carouselElementAction = new CarouselElementAction();
            carouselElementAction.Type = CarouselElementActionType.OpenPhoto;
            double belkiLow = 0, zhiryLow = 0, uglevodyLow = 0, belkiHigh = 0, zhiryHigh = 0, uglevodyHigh = 0;
            double curBelki = 0, curZhiry = 0, curUglevody = 0;
            double foodPercent = 0;
            double belkiPercent = 0, zhiryPercent = 0, uglevodyPercent = 0;
            double dayKkal = 0;
            string foodTime = "";
            try
            {
                
                var user = db.Users.Single(usr => usr.chatId == chatId);
                var cartObject = JsonConvert.DeserializeObject<CartObject>(user.cart);
                var choosenProducts = JsonConvert.DeserializeObject<List<int>>(user.choosenProducts);
                List<int> sportDays = JsonConvert.DeserializeObject<List<int>>(user.sportDays);

                //if (curDay == 8) curDay = (int)DateTime.Now.DayOfWeek;
                int nextDay = curDay + 1;

                if (nextDay == 8)
                    nextDay = 1;

                foreach (var o in cartObject.orders)
                {
                    sum += o.price * o.number;
                }


                categories = db.CategoriesDostavkas.ToList().ConvertAll<CategoriesDostavka>(c =>
                    new CategoriesDostavka()
                    {
                        categoryId = c.categoryId,
                        name = c.name,
                        btnName = c.btnName,
                        kbColor = c.kbColor,
                    });

                allProducts = db.ProductsDostavkas.Where(p => p.categoryId != 0 &&
                                JsonConvert.DeserializeObject<List<int>>(p.weekDays).Exists(day => day == curDay)).
                                 ToList().ConvertAll<ProductsDostavka>(e=>new ProductsDostavka() 
                                 {
                                     id = e.id,
                                     article = e.article,
                                     colorId = e.colorId,
                                     categoryId = e.categoryId,
                                     name = e.name,
                                     fullName = e.fullName,
                                     descriptionCarousel = e.descriptionCarousel,
                                     price = Convert.ToDouble(e.price),
                                     photo = e.photo,
                                     photoCarousel = e.photoCarousel,
                                     kkal = e.kkal,
                                     foodType = JsonConvert.DeserializeObject<List<int>>(e.foodType),
                                     belki = Convert.ToDouble(e.belki),
                                     zhiry = Convert.ToDouble(e.zhiry),
                                     uglevody = Convert.ToDouble(e.uglevody),
                                 });

                ProductsDostavka water = new ProductsDostavka();
                water = allProducts.Find(p => p.article.Equals("55"));
                allProducts.Remove(water);
                //allProducts.RemoveAll(p => !p.foodType.Contains(curCategory));
                if (choosenProducts.Count > 0)
                    allProducts.RemoveAll(p => choosenProducts.Contains(p.id));

                switch (user.track)
                {
                    case 1:
                        belkiLow = 1.4;
                        belkiHigh = 2;

                        zhiryLow = 1;
                        zhiryHigh = 1.1;

                        uglevodyLow = 2.4;
                        uglevodyHigh = 3;
                        break;

                    case 2:
                        belkiLow = 1.2;
                        belkiHigh = 1.7;

                        zhiryLow = 0.9;
                        zhiryHigh = 1;

                        uglevodyLow = 2;
                        uglevodyHigh = 2.6;
                        break;

                    case 3:
                        belkiLow = 1.6;
                        belkiHigh = 2.2;

                        zhiryLow = 1.1;
                        zhiryHigh = 1.2;

                        uglevodyLow = 2.8;
                        uglevodyHigh = 3.4;
                        break;
                }

                switch (curCategory)
                {
                    case 1:
                        allProducts.RemoveAll(p => p.categoryId == 1);

                        foodPercent = 0.3;
                        belkiPercent = 0.3;
                        uglevodyPercent = 0.4;
                        zhiryPercent = 0.2;
                        foodTime = "🥐Завтрак";
                        randomFood = allProducts.FindAll(ap => (ap.categoryId != 1) && ap.zhiry <= zhiryLow * user.weight * zhiryPercent && ap.uglevody <= uglevodyLow * user.weight * uglevodyPercent);
                        
                        //Углеводы - 0.4
                        //Белки - 0.3
                        //Жиры - 0.2
                        //Кнопка ещё один вариант
                        //web
                        break;

                    case 2:
                        foodPercent = 0.4;
                        belkiPercent = 0.3;
                        uglevodyPercent = 0.3;
                        zhiryPercent = 0.4;
                        foodTime = "🍲Обед";
                        randomFood = allProducts.FindAll(ap => ap.categoryId == 1 && ap.zhiry <= zhiryLow * user.weight * zhiryPercent && ap.uglevody <= uglevodyLow * user.weight * uglevodyPercent);
                        break;

                    case 3:
                        allProducts.RemoveAll(p => p.categoryId == 1);

                        foodPercent = 0.1;
                        belkiPercent = 0.2;
                        uglevodyPercent = 0.2;
                        zhiryPercent = 0.2;
                        foodTime = "🥪Перекус";
                        //ap.categoryId == 5 || ap.categoryId == 4
                        randomFood = allProducts.FindAll(ap => (ap.categoryId != 1) && ap.zhiry <= zhiryLow * user.weight * zhiryPercent && ap.uglevody <= uglevodyLow * user.weight * uglevodyPercent);
                        break;

                    case 4:
                        allProducts.RemoveAll(p => p.categoryId == 1);

                        foodPercent = 0.3;
                        belkiPercent = 0.2;
                        uglevodyPercent = 0.2;
                        zhiryPercent = 0.2;
                        randomFood = allProducts.FindAll(ap => (ap.categoryId != 1) && ap.zhiry <= zhiryLow * user.weight * zhiryPercent && ap.uglevody <= uglevodyLow * user.weight * uglevodyPercent);
                        foodTime = "🥗Ужин";
                        break;
                }

                
                double maxKkal = Math.Round(curDayKkal * 1.2 * foodPercent);
                double minKkal = Math.Round(curDayKkal * 0.9 * foodPercent);

                Random rand = new Random();
                if (choosenProducts.Count > 0)
                    randomFood.RemoveAll(p => choosenProducts.Contains(p.id));

                int randomBludo = rand.Next(0, randomFood.Count);

                if (curCategory == 3)
                {
                    products.Add(randomFood.Find(rf => rf.kkal <= maxKkal));
                }
                else
                {
                    products.Add(randomFood[randomBludo]);
                }

                curBelki = products[0].belki;
                curZhiry = products[0].zhiry;
                curUglevody = products[0].uglevody;
                dayKkal = products[0].kkal;
                choosenProducts.Add(products[0].id);
                ProductsDostavka tmp = new ProductsDostavka();
                for (i = 0; i < allProducts.Count; i++)
                {
                    tmp = allProducts[i];
                    allProducts.RemoveAt(i);
                    allProducts.Insert(rand.Next(allProducts.Count), tmp);
                }



                foreach (var ap in allProducts)
                {
                    //if (dayKkal + ap.kkal <= maxKkal) //curBelki <= belkiLow * weight * foodPercent && curUglevody + ap.uglevody < uglevodyHigh * weight * foodPercent)
                    if (curBelki + ap.belki <= belkiHigh * user.weight * belkiPercent && 
                        curUglevody + ap.uglevody <= uglevodyHigh * user.weight * uglevodyPercent)// && 
                        //curZhiry + ap.zhiry <= zhiryHigh * weight * zhiryPercent)
                    {
                        if (!products.Exists(p => p.categoryId == ap.categoryId))
                        {
                            if (true)//curUglevody + ap.uglevody < uglevodyHigh * weight * foodPercent curBelki < belkiHigh * weight * foodPercent && curZhiry < zhiryHigh * weight * foodPercent && curUglevody < uglevodyHigh * weight * foodPercent)
                            {

                                curBelki += ap.belki;
                                curZhiry += ap.zhiry;
                                curUglevody += ap.uglevody;
                                dayKkal += ap.kkal;
                                products.Add(ap);
                                choosenProducts.Add(ap.id);
                            }
                        }
                    }
                    //else break;
                }

                //if (dayKkal < minKkal)
                //{
                //    if (curCategory != 3)
                //    {
                //        products.Add(allProducts.Find(ap => !choosenProducts.Contains(ap.id) && ap.zhiry <= zhiryLow * weight * zhiryPercent && ap.uglevody <= uglevodyLow * weight * uglevodyPercent && ap.categoryId != 7));
                //        curBelki += products[products.Count - 1].belki;
                //        curZhiry += products[products.Count - 1].zhiry;
                //        curUglevody += products[products.Count - 1].uglevody;
                //        dayKkal += products[products.Count - 1].kkal;
                //        choosenProducts.Add(products[products.Count - 1].id);
                //    }
                //    //else
                //    //    products.Add(allProducts.Find(ap => !choosenProducts.Contains(ap.id) && ap.kkal <= maxKkal - minKkal));
                //    //choosenProducts.Add(products[products.Count - 1].id);
                //}

                if (!products.Exists(p => p.categoryId == 7))
                    products.Add(water);
                    //(p => p.article.Equals("55")))

                //if (curCategory != 4)
                //{
                //    SqlCommand updCart = new SqlCommand("UPDATE Users SET choosenProducts = @choosenProducts WHERE chatId = @chatId;", Con);
                //    updCart.Parameters.AddWithValue("@chatId", chatId);
                //    updCart.Parameters.AddWithValue("@choosenProducts", JsonConvert.SerializeObject(choosenProducts));
                //    updCart.ExecuteNonQuery();
                //}
                //else
                //{
                //    SqlCommand updCart = new SqlCommand("UPDATE Users SET choosenProducts = @choosenProducts WHERE chatId = @chatId;", Con);
                //    updCart.Parameters.AddWithValue("@chatId", chatId);
                //    updCart.Parameters.AddWithValue("@choosenProducts", "[]");
                //    updCart.ExecuteNonQuery();
                //}

                nextCatalog = curProduct + 9;
                prevCatalog = curProduct - 9;

                if (curProduct > 0 && products.Count > 6)
                {
                    if (nextCatalog > products.Count) nextCatalog = products.Count - (products.Count - curProduct);

                    if (prevCatalog < 0) prevCatalog = 0;
                }

                for (i = curProduct; i < products.Count; i++)
                {
                    var jsPhoto = JsonConvert.DeserializeObject<CatalogPhotoObject>(products[i].photoCarousel);

                    desc = products[i].descriptionCarousel; //+ " " + products[i].weight;
                    if (desc.Length > 80) desc = desc.Substring(0, 77) + "..."; //desc.Substring(0, 77)

                    templateBuilder.AddTemplateElement(new CarouselElement()
                    {
                        Title = products[i].fullName,
                        Description = desc + " | " + products[i].kkal + " ккал\n" +
                        $"Б\\Ж\\У: {products[i].belki}г\\{products[i].zhiry}г\\{products[i].uglevody}г",
                        PhotoId = jsPhoto.owner_id + "_" + jsPhoto.id + "_" + jsPhoto.access_key,
                        Buttons = new List<MessageKeyboardButton>()
                        {
                            new MessageKeyboardButton(){
                                Action = new MessageKeyboardButtonAction(){ Label = "Добавить в корзину " + products[i].price + "р",
                                    Payload = "{\"button\":\"selectAddToCart-" + products[i].categoryId + "-" + products[i].id + "-" + curDayKkal + "\"}",
                                    Type = KeyboardButtonActionType.Text },
                                Color = KeyboardButtonColor.Positive
                            },
                            //new MessageKeyboardButton(){
                            //    Action = new MessageKeyboardButtonAction(){ Label = "Подробнее",
                            //        Payload = "{\"button\":\"selectAddToCart-" + curCategory + "-" + i + "\"}",
                            //        Type = KeyboardButtonActionType.Text },
                            //    Color = KeyboardButtonColor.Default
                            //},
                        },
                        Action = carouselElementAction,
                    });

                    if (templateBuilder.Elements.Count == 9 && products.Count > 10)
                        break;
                }

                if (products.Count > 10)
                {
                    switch (curWay)
                    {
                        case 1:
                            if (curProduct < (products.Count - 9))
                                naviState = 1;
                            else
                                naviState = 2;
                            break;
                        case 2:
                            if (curProduct == 0)
                                naviState = 1;
                            else
                                naviState = 2;
                            break;
                        default:
                            naviState = 2;
                            break;
                    }

                    switch (naviState)
                    {
                        case 1:
                            templateBuilder.AddTemplateElement(new CarouselElement()
                            {
                                Title = ".",
                                Description = ".",
                                PhotoId = PHOTOIDNEXT,
                                Buttons = new List<MessageKeyboardButton>()
                                {
                                    new MessageKeyboardButton() {
                                        Action = new MessageKeyboardButtonAction(){ Label = ">> Следующие " + (products.Count - nextCatalog).ToString(),
                                            Payload = "{\"button\":\"selectProduct-" + products[nextCatalog].categoryId + "-" + nextCatalog + "-1\"}",
                                            Type = KeyboardButtonActionType.Text },
                                        Color = KeyboardButtonColor.Primary
                                    },
                                },
                                Action = carouselElementAction,
                            });
                            break;

                        case 2:
                            templateBuilder.AddTemplateElement(new CarouselElement()
                            {
                                Title = ".",
                                Description = ".",
                                PhotoId = PHOTOIDNEXT,
                                Buttons = new List<MessageKeyboardButton>()
                                {
                                    new MessageKeyboardButton() {
                                        Action = new MessageKeyboardButtonAction(){ Label = "<< Предыдущие " + curProduct,
                                            Payload = "{\"button\":\"selectProduct-" + products[prevCatalog].categoryId + "-" + prevCatalog + "-2\"}",
                                            Type = KeyboardButtonActionType.Text },
                                        Color = KeyboardButtonColor.Primary
                                    },
                                },
                                Action = carouselElementAction,
                            });
                            break;
                    }
                }

                @params.Message = foodTime + "\n" +
                    "Калории: " + dayKkal + " ккал \n" +
                    $"Б\\Ж\\У: {curBelki}г\\{curZhiry}г\\{curUglevody}г \n\n" +
                    $"Если хотите подобрать блюда ещё раз, нажмите кнопку повторно😉";
                @params.Template = templateBuilder.Build();
                @params.UserId = chatId;
                @params.RandomId = GetRandomId();
                client.Messages.SendAsync(@params);

            }
            catch (Exception ee)
            {
                @params.Message = "‼Ошибка в ShowProductCaruselMain: " + ee.Message;
                @params.Attachments = null;
                @params.Keyboard = null;
                @params.UserId = 59111081;
                @params.RandomId = GetRandomId();
                client.Messages.SendAsync(@params);
            }
        }

        private static readonly RandomNumberGenerator Rng = RandomNumberGenerator.Create();
        private int GetRandomId()
        {

            var intBytes = new byte[4];

            Rng.GetBytes(intBytes);

            return BitConverter.ToInt32(intBytes, 0);
        }
    }
}