using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Newtonsoft.Json;
using Quizzer.Extensions;
using Quizzer.Models;
using Quizzer.OpenIDConnect;
using Quizzer.Persistens;
using System.Collections;
using System.IdentityModel.Tokens.Jwt;

namespace Quizzer.Pages
{

    public class IndexModel : PageModel
    {

        // Generat landing page
        // Teachers get navigation options
        // Students are presented with selection of available tests

        [BindProperty]
        public string PageQuizzID { get; set; }

        [BindProperty]
        public List<JournalHtml> PageTests { get; set; }

        [BindProperty]
        public OpenIDUCNData ucnData { get; set; }

        [BindProperty]
        public string UserID { get; set; }

        [BindProperty]
        public string StudentState { get; set; }

        [BindProperty]
        public MCQuestion PageMCQuestion { get; set; }

        [BindProperty]
        public List<MCQuestion> PageMCQuestionReview { get; set; }

        [BindProperty]
        public List<List<bool>> PageMCResponseReview { get; set; }

        [BindProperty]
        public List<int> PageMCRandomized { get; set; }

        [BindProperty]
        public string myFullName { get; set; }

        [BindProperty]
        public List<ChartConnector> PageChartConnectors { get; set; }

        private readonly ILogger<IndexModel> _logger;

        public IndexModel(ILogger<IndexModel> logger)
        {
            _logger = logger;
        }

        private bool isDebug;
        private string KCUserID { get; set; }

        private DbOps dbManager = new();

        private OpenIDConnectUtils OpenIDUtils = new();

        private void DumpEnvironment()
        {
            Console.WriteLine("HEADER DUMP START");
            foreach (var e in HttpContext.Request.Headers)
            {
                Console.WriteLine(e.Key + ":" + e.Value);
            }
            Console.WriteLine("HEADER DUMP END");
            Console.WriteLine("ENVIRONMENT DUMP START");
            foreach (DictionaryEntry e in System.Environment.GetEnvironmentVariables())
            {
                Console.WriteLine(e.Key + ":" + e.Value);
            }
            Console.WriteLine("ENVIRONMENT DUMP END");
        }

        public void Common()
        {
            isDebug = MyConfiguration.Get()["DEBUG"] == "Y";
            string? ucnDataJson = OpenIDUtils.GetJwtClaim(HttpContext, "ucn");

            KCUserID = OpenIDUtils.GetJwtClaim(HttpContext, "sub");
            ucnData = JsonConvert.DeserializeObject<OpenIDUCNData>(ucnDataJson);
            UserID = OpenIDUtils.GetJwtClaim(HttpContext, "email").HashSHA256();
            myFullName = OpenIDUtils.GetJwtClaim(HttpContext, "name");
        }

        private void Msg(string msg)
        {
            Boolean debug = true;
            if (debug)
            {
                Console.WriteLine(msg);
            }
        }

        private void Journal(string Msg)
        {
            Console.WriteLine("JOURNAL:" + Msg);
        }


        // =============================================================
        //        From SSO session:
        // OIDC_CLAIM_email = "KAJE@ucn.dk"
        // OIDC_CLAIM_family_name = "Jeppesen"
        // OIDC_CLAIM_given_name = "Karsten"
        // OIDC_CLAIM_name = "Karsten Jeppesen"

        List<Question> PopulateQList(string theCategory)
        {
            // Get the questions in the category
            List<Question> list = dbManager.GetQuestions(theCategory);
            // Now get the subordinate categories
            List<Cat> catList = dbManager.GetChildCategories(theCategory);
            foreach (Cat cat in catList)
            {
                list.AddRange(PopulateQList(cat.CId));
            }
            return list;
        }

        private void PrepareForUser(string theRole, string theClass)
        {

            foreach (Quizz theQuizz in dbManager.GetQuizzesClass(theClass))
            {
                // Make sure that for a quizz is generated for this individual
                Journal2 theJournal = dbManager.GetJournal2(UserID, theQuizz.QuizzId);
                if (theJournal == null)
                {
                    // Make up a new journal
                    Journal2 newJournal = new()
                    {
                        PID = UserID,
                        QuizzID = theQuizz.QuizzId,
                        Category = theQuizz.Category,
                        Anonymous = theQuizz.Anonymous,
                        IsOpen = 1,
                        Score = 0,
                        ScoreAcc = 0,
                    };
                    //List<Item>items = JsonConvert.DeserializeObject<List<Item>>(theJournal.JournalJson);
                    newJournal.Items = new();
                    List<Question> myQuestions = PopulateQList(theQuizz.Category);
                    //List<Question> myQuestions = dbManager.GetQuestions(theQuizz.Category);
                    int theSize = (myQuestions.Count < theQuizz.QSize) ? myQuestions.Count : theQuizz.QSize;
                    Random rnd = new Random();
                    while (theSize < myQuestions.Count)
                    {
                        myQuestions.RemoveAt(rnd.Next(myQuestions.Count));
                    }
                    // we should now have a random selection of theSize questions
                    // Lets mix the deck
                    for (int indx = 0; indx < myQuestions.Count; indx++)
                    {
                        int target = rnd.Next(myQuestions.Count);
                        myQuestions.Add(myQuestions[target]);
                        myQuestions.RemoveAt(target);
                    }
                    foreach (Question question in myQuestions)
                    {
                        newJournal.ScoreAcc++;
                        newJournal.Items.Add(new Journal2Item
                        {
                            QuestionID = question.QuestionID,
                            IsOpen = 1,
                            Score = 0,
                            MaxScore = 1,
                        });
                    }
                    dbManager.PostJournal2(newJournal);
                }
            }
        }

        private void BuildTestSelection()
        {
            List<JournalHtml> myTests = new();
            List<Journal2> myJournals = dbManager.GetJournal2(UserID);
            foreach (Journal2 myJournal in myJournals)
            {
                Quizz theQuizz = dbManager.GetQuizz(myJournal.QuizzID);
                if (theQuizz == null) continue;
                JournalHtml myHtml = new()
                {
                    Journal = myJournal,
                    Text = theQuizz.Descr,
                };
                myTests.Add(myHtml);
            }
            PageTests = myTests;
        }

        private bool PresentQuestion()
        {
            Journal2 myJournal = dbManager.GetJournal2(UserID, PageQuizzID);
            if (myJournal == null)
            {
                Response.Cookies.Delete("PageQuizzID");
                return false;
            }
            //List<Item> myItems = JsonConvert.DeserializeObject<List<Item>>(myJournal.JournalJson);
            Random rnd = new Random();
            foreach (var item in myJournal.Items)
            {
                if (item.IsOpen == 1)
                {
                    // Get the question
                    MCQuestion myMCQuestion = dbManager.GetMCQuestion(item.QuestionID);
                    List<int> myRndSeq = new List<int>();
                    for (int indx = 0; indx < myMCQuestion.AList.Count(); indx++)
                    {
                        myRndSeq.Add(indx);
                        myMCQuestion.AList[indx].Aok = false;
                    }
                    PageMCRandomized = new List<int>();
                    while (myRndSeq.Count > 0)
                    {
                        int indx = rnd.Next(myRndSeq.Count);
                        PageMCRandomized.Add(myRndSeq[indx]);
                        myRndSeq.RemoveAt(indx);
                    }
                    PageMCQuestion = myMCQuestion;
                    return true;
                }
            }
            FinalizeTest();
            return false;
        }

        private void FinalizeTest()
        {
            Journal2 myJournal = dbManager.GetJournal2(UserID, PageQuizzID);
            myJournal.IsOpen = 0;
            dbManager.UpdateJournal2(myJournal);
            Response.Cookies.Delete("PageQuizzID");
        }

        private void RegisterAnswer()
        {
            Journal2 myJournal = dbManager.GetJournal2(UserID, PageQuizzID);
            foreach (var item in myJournal.Items)
            {
                if (item.IsOpen == 1)
                {
                    // Get the question
                    MCQuestion myMCQuestion = dbManager.GetMCQuestion(item.QuestionID);
                    if (myMCQuestion != null)
                    {
                        int theScore = item.MaxScore;
                        int answers = 0;
                        item.ReplyMC = new();
                        for (int indx = 0; indx < myMCQuestion.AList.Count(); indx++)
                        {
                            item.ReplyMC.Add(PageMCQuestion.AList[indx].Aok);
                            if (myMCQuestion.AList[indx].Aok != PageMCQuestion.AList[indx].Aok) theScore = 0;
                            if (PageMCQuestion.AList[indx].Aok) answers++;
                        }
                        if (answers != 1) return; // Must have one answer and one only
                        item.Score = theScore;
                        myJournal.Score += theScore;
                        item.IsOpen = 0;
                        dbManager.UpdateJournal2(myJournal);
                        // Now register statistics
                        List<int> counter = new List<int>();
                        for (int indx = 0; indx < myMCQuestion.AList.Count(); indx++)
                        {
                            if (PageMCQuestion.AList[indx].Aok) { counter.Add(1); } else { counter.Add(0); }
                        }
                        dbManager.UpdateStats(PageQuizzID, item.QuestionID, counter);
                        PageMCQuestion.AList.Clear();
                    }
                    return;
                }
            }
            return;
        }

        private void PrepareReview()
        {
            PageMCQuestionReview = new();
            PageMCResponseReview = new();
            List<StatisticsStudentByCategory> StatStudent = new();
            Journal2 myJournal = dbManager.GetJournal2(UserID, PageQuizzID);
            if (myJournal == null)
            {
                Response.Cookies.Delete("PageQuizzID");
                return;
            }

            for (int index = 0; index < myJournal.Items.Count; index++)
            {
                string background;
                MCQuestion question = dbManager.GetMCQuestion(myJournal.Items[index].QuestionID);
                PageMCQuestionReview.Add(question);
                PageMCResponseReview.Add(myJournal.Items[index].ReplyMC);
                // create statistics
                StatisticsStudentByCategory theStat = StatStudent.Find(x => x.CategoryID == question.Category);
                if (theStat == null)
                { // need a new one
                    Cat cat = dbManager.GetCat(question.Category);
                    StatStudent.Add(new StatisticsStudentByCategory { CategoryID = cat.CId, CategoryName = cat.Txt });
                    theStat = StatStudent[StatStudent.Count - 1];
                }
                theStat.Update(myJournal.Items[index].Score, myJournal.Items[index].MaxScore);
                // https://social.msdn.microsoft.com/Forums/en-US/7f96525d-7253-4f08-87f8-88ae526834f9/razor-pages-with-chartjs?forum=aspdotnetcore
                PageChartConnectors = new List<ChartConnector>();
                //background = "getRandomColor()";
                var random = new Random();
                foreach (StatisticsStudentByCategory item in StatStudent)
                {
                    background = String.Format("#{0:X6}", random.Next(0x1000000)); // = "#A197B9"
                    PageChartConnectors.Add(new ChartConnector
                    {
                        ChartLabel = item.CategoryName,
                        ChartData = item.percentage.ToString(),
                        ChartBackground = background,
                        ChartBorder = "#FFBBBB"
                    });
                }
                //PageChartConnectors.Add(new ChartConnector
                //{
                //    ChartLabel = "100%",
                //    ChartData = "100",
                //    ChartBackground = "#000000",
                //    ChartBorder = "#FFBBBB"
                //});
                //PageChartConnectors.Add(new ChartConnector { ChartLabel = "Jan", ChartData = "31", ChartBackground = "#FF0000", ChartBorder = "#000000" });
            }
        }

        private void CheckPageQuizzID()
        {
            if (PageQuizzID == null)
            {
                //PrepareForUser(ucnData.theRole, ucnData.theClass.FirstOrDefault());
                foreach (var item in ucnData.theClass)
                {
                    PrepareForUser(ucnData.theRole, item);
                }
                BuildTestSelection();
                if (ucnData.theRole == "student" || ucnData.theRole == "developer") StudentState = "QuizzSelect";
            }
            else
            {
                if (!QuizzRunning())
                {
                    //PageQuizzID = null;
                    if (ucnData.theRole == "student" || ucnData.theRole == "developer") StudentState = "QuizzSelect";
                    PrepareForUser(ucnData.theRole, ucnData.theClass.FirstOrDefault());
                    BuildTestSelection();
                    // Review selected test?
                    PrepareReview();
                }
            }
        }

        private void CheckTheClass()
        {
            if (ucnData.theClass.Count > 0)
            {
                foreach (var item in ucnData.theClass)
                {
                    if (item.Contains("-CSD-"))
                    {
                        if (dbManager.GetTheClasses().Find(x => x.Name == item) == null) dbManager.CreateTheClass(new TheClass { Name = item });
                    }
                }
            }
        }

        public IActionResult OnGet(string category, string count)
        {
            try
            {
                // if the entity can not be categorized then send him to classselect
                Common();
            }
            catch
            {
                return Redirect("https://ClassSelect.a.ucnit.eu");
            }
            if ((ucnData.theClass.Count == 0) || (ucnData.theClass[0] == "PleaseSelectAClass"))
            {
                // No class found
                return Redirect("https://ClassSelect.a.ucnit.eu");
            }
            PageQuizzID = HttpContext.Request.Cookies["PageQuizzID"];
            CheckPageQuizzID();
            // Next line should be replaced by call to KeyCloakGetUsersGroups
            // CheckTheClass();
            return Page();
        }

        private bool QuizzRunning()
        {
            StudentState = "QuizzRunning";
            return PresentQuestion();
        }

        public IActionResult OnPost(string action, string value, string quizzInProgress, string target)
        {
            Common();
            switch (action)
            {
                case "startTest":
                    // NEW: Coverage: register who takes the test
                    Quizz theQuizz = dbManager.GetQuizz(value);
                    if (! theQuizz.Anonymous)
                    {   // Only register coverage if the test is not anonymous
                        dbManager.SetCoverage(OpenIDUtils.GetJwtClaim(HttpContext, "email"), OpenIDUtils.GetJwtClaim(HttpContext, "name"), ucnData.theClass.FirstOrDefault());
                    }
                    if (isDebug) Console.WriteLine(OpenIDUtils.GetJwtClaim(HttpContext, "name") + ": REMOTE ADDR: " + HttpContext.Request.Headers["X-Forwarded-For"]);
                    Console.WriteLine(OpenIDUtils.GetJwtClaim(HttpContext, "name") + ": REMOTE ADDR: " + HttpContext.Request.Headers["X-Forwarded-For"]);
                    PageQuizzID = value;
                    QuizzRunning();
                    break;
                case "reviewTest":
                    PageQuizzID = value;
                    break;
                case "QuizzRunning":
                    QuizzRunning();
                    break;
                case "registerAnswer":
                    PageQuizzID = quizzInProgress;
                    RegisterAnswer();
                    break;
                case "deleteMyTest": //Student should not be able to delete journal as this resets the journal
                    dbManager.DeleteJournal2(UserID, target);
                    break;
                default:
                    break;
            }
            if (PageQuizzID != null)
            {
                Response.Cookies.Append("PageQuizzID", PageQuizzID, new Microsoft.AspNetCore.Http.CookieOptions
                {
                    Secure = true,
                    HttpOnly = true,
                    SameSite = Microsoft.AspNetCore.Http.SameSiteMode.None,
                });
            }
            return Redirect("/");
        }

    }
}