using DbConnectionLibrairie;
using Entities;
using ManagerInterfaces;
using Microsoft.EntityFrameworkCore;
using Model;
using OrderCriterias;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EntityManagers
{
    public class QuestionEntityManager(MyDbContext dbContext) : IQuestionManager<QuestionEntity>
    {
        private MyDbContext dbContext = dbContext;

        private IQueryable<QuestionEntity> trier(IQueryable<QuestionEntity> query, QuestionOrderCriteria orderCriteria)
        {
            switch(orderCriteria)
            {
                case QuestionOrderCriteria.ById:
                    return query.OrderBy(q => q.Id);
                case QuestionOrderCriteria.ByContent:
                    return query.OrderBy(q => q.Content);
                case QuestionOrderCriteria.ByDifficulty:
                    return query.OrderBy(q => q.Difficulty);
                case QuestionOrderCriteria.ByNbFalls:
                    return query.OrderBy(q => q.NbFalls);
                case QuestionOrderCriteria.ByIdChapter:
                    return query.OrderBy(q => q.Chapter);
            }
            return query;
        }

        public async Task<QuestionEntity> addQuestion(QuestionEntity question)
        {
            var tmp = await dbContext.Questions.Where(q => q.Equals(question)).FirstOrDefaultAsync();
            if (tmp != null) // <=> he already exist
            {
                return tmp!;
            }
            dbContext.Questions.Add(question);
            await dbContext.SaveChangesAsync();
            return await dbContext.Questions.Where(q => q.Equals(question)).FirstAsync();
        }

        public async Task<IEnumerable<QuestionEntity>> addQuestions(IEnumerable<QuestionEntity> questions)
        {
            var tmp = new List<QuestionEntity>();
            foreach (var q in questions)
            {
                tmp.Add(addQuestion(q).Result);
            }
            return await Task.FromResult<IEnumerable<QuestionEntity>>(tmp);
        }

        public int getNbElements()
        {
            return dbContext.Questions.CountAsync().Result;
        }

        public async Task<QuestionEntity?> getQuestion(uint id)
        {
            return await Task.FromResult<QuestionEntity?>(dbContext.Questions.Where(q => q.Id == id).FirstOrDefault());
        }

        public async Task<(int nbPages, IEnumerable<QuestionEntity>? questions)> getQuestions(int nb, int count, QuestionOrderCriteria orderCriteria = QuestionOrderCriteria.ById)
        {
            int nbEl = getNbElements();
            if (nb < 0 || count < 0 || nb > nbEl / count) return await Task.FromResult<(int nbPages, IEnumerable<QuestionEntity>? questions)>((nbEl / count, null));
            var tmp = trier(dbContext.Questions, orderCriteria);
            return await Task.FromResult<(int nbPages, IEnumerable<QuestionEntity>? questions)>((nbEl / count, tmp.Skip((nb - 1) * count).Take(count)));
        }

        public async Task<(int nbPages, IEnumerable<QuestionEntity>? questions)?> getQuestionsByChapterAndDifficulty(int idChapter, int difficulty, int nb, int count, QuestionOrderCriteria orderCriteria = QuestionOrderCriteria.ById)
        {
            if (nb < 0 || count < 0 || difficulty < 1 || difficulty > 3 || !dbContext.Chapters.Where(c => c.Id == idChapter).AnyAsync().Result)
                return await Task.FromResult<(int nbPages, IEnumerable<QuestionEntity>? questions)?>(null);
            int nbEl = getNbElements();
            if (nb > nbEl / count) return await Task.FromResult<(int nbPages, IEnumerable<QuestionEntity>? questions)?>((nbEl / count, null));
            var tmp = trier(dbContext.Questions, orderCriteria);
            return await Task.FromResult<(int nbPages, IEnumerable<QuestionEntity>? questions)?>((nbEl / count, tmp.Skip((nb - 1) * count).Take(count)));
        }

        public async Task<QuestionEntity?> removeQuestion(QuestionEntity question)
        {
            var tmp = await dbContext.Questions.Where(q => q.Equals(question)).FirstOrDefaultAsync();
            if (tmp == null) return tmp;
            dbContext.Questions.Remove(tmp);
            await dbContext.SaveChangesAsync();
            return tmp;
        }

        public Task<QuestionEntity?> removeQuestion(uint id)
        {
            var tmp = getQuestion(id);
            if (tmp.Result == null) return tmp;
            dbContext.Questions.Remove(tmp.Result);
            dbContext.SaveChangesAsync();
            return tmp;
        }

        public async Task<QuestionEntity?> updateQuestion(uint id, QuestionEntity question)
        {
            var tmp = getQuestion(id);
            if (tmp.Result == null) return await tmp;
            tmp.Result.Chapter = question.Chapter;
            tmp.Result.Content = question.Content;
            tmp.Result.IdChapter = question.IdChapter;
            tmp.Result.AnswerGood = question.AnswerGood;
            tmp.Result.Difficulty = question.Difficulty;
            await dbContext.SaveChangesAsync();
            return await tmp;
        }

        public async Task<QuestionEntity?> updateQuestionNbFalls(uint id)
        {
            var tmp = getQuestion(id);
            if (tmp.Result == null) return await tmp;
            tmp.Result.NbFalls++;
            uint nbFalls = tmp.Result.NbFalls;
            if (nbFalls == 50) tmp.Result.Difficulty = 2;
            if (nbFalls == 150) tmp.Result.Difficulty = 3;
            await dbContext.SaveChangesAsync();
            return await tmp;
        }
    }
}
