using Microsoft.AspNetCore.Http.HttpResults;
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.Diagnostics;
using System.IdentityModel.Tokens.Jwt;
using System.Text;

namespace Quizzer.Pages
{
    public class QuestionsModel : PageModel
    {
        [BindProperty]
        public OpenIDUCNData ucnData { get; set; }

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

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

        [BindProperty]
        public bool isSubmittable { get; set; }

        [BindProperty]
        public List<Question> questionsInCat { get; set; }

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

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

        [BindProperty]
        public IFormFile Upload { get; set; }

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


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

        private DbOps qManager = new DbOps();

        private OpenIDConnectUtils OpenIDUtils = new();

        private const string cookieName = "QuestionCookie";

        private void GetMyCookie()
        {
            string jsonString = HttpContext.Request.Cookies[cookieName];
            if (jsonString != null)
            {
                questionCookie = JsonConvert.DeserializeObject<MCQuestion>(jsonString);
                return;
            }
            // Here if no cookie found
            questionCookie = new MCQuestion
            {
                QuestionText = "",
                AList = new List<Alternative> { new Alternative
                        {
                            Aok = false,
                            Atxt = "",
                            Counter = 0
                        }
                    }
            };
            // Save the new cookie
            SetMyCookie();
        }

        private void SetMyCookie()
        {
            string jsonResult = JsonConvert.SerializeObject(questionCookie);
            Response.Cookies.Append(cookieName, jsonResult, new Microsoft.AspNetCore.Http.CookieOptions
            {
                Secure = true,
                HttpOnly = true,
                SameSite = Microsoft.AspNetCore.Http.SameSiteMode.None,
            });
        }

        private void RemoveMyCookie()
        {
            Response.Cookies.Delete(cookieName);
        }


        public void AlwaysIn()
        {
            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");
            GetMyCookie();
        }

        public void AlwaysOut()
        {
            CatMenu = qManager.MakeCList(UserID, "DropDown", questionCookie.Category);
            isSubmittable = true;
            if (questionCookie.Category == "" || questionCookie.Category == null)
            {
                isSubmittable = false;
                questionsInCat = null;
            }
            else
            {
                questionsInCat = qManager.GetQuestions(questionCookie.Category);
                mcQuestionsInCat = new();
                foreach ( var item in questionsInCat )
                {
                    MCQuestion newQ= new MCQuestion();
                    newQ.QuestionID = item.QuestionID;
                    newQ.QuestionText = item.QuestionText;
                    newQ.AList = JsonConvert.DeserializeObject<List<Alternative>>(item.ContentJson);
                    mcQuestionsInCat.Add(newQ);
                }
            }
            try
            {
                isSubmittable = questionCookie.QuestionText != "" && questionCookie.AList.Where(x => x.Aok == true).Count() == 1 && questionCookie.Category != null;

            }
            catch
            {
                RemoveMyCookie();
                GetMyCookie();
                isSubmittable = false;
            }
        }

        /// <summary>
        /// Will attempt to extract questions encoded in the Eiken format.
        /// The answer letters (A,B,C etc.) and the word "ANSWER" must be capitalised as shown below, otherwise the import will fail.
        /// What is True?
        /// A. True
        /// B. False
        /// ANSWER: A
        /// 
        /// What is True?
        /// A) True
        /// B) False
        /// ANSWER: A
        /// 
        /// </summary>
        /// <param name="theFile">
        /// A byte array of the uploaded text file
        /// </param>
        private void EikenDecode(byte[] theFile)
        {
            string[] lines = System.Text.Encoding.Default.GetString(theFile).Split(new string[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
            char state = 'q'; // state: looking for question text
            MCQuestion theQuestion = new(); ;
            foreach (string theLine in lines)
            {
                if (state == 'q')
                {
                    if (theLine.Length == 0) continue;
                    // something here
                    theQuestion = new();
                    theQuestion.QuestionText = theLine;
                    state = 'A'; // looking for first alternative
                    continue;
                }
                if (theLine[0] == state && (theLine[1] == '.' || theLine[1] == ')'))
                { // alternative
                    theQuestion.AList.Add(new Alternative
                    {
                        Aok = false,
                        Atxt = theLine.Substring(3, theLine.Length - 3),
                    });
                    state++;
                    continue;
                }
                if (theLine.StartsWith("ANSWER: "))
                {
                    int correct = theLine[8] - 'A';
                    theQuestion.AList[correct].Aok = true;
                    theQuestion.Category = questionCookie.Category;
                    theQuestion.QuestionType = questionCookie.QuestionType;
                    qManager.InsertMCQuestion(theQuestion);
                    state = 'q';
                    continue;
                }
            }
        }

        public IActionResult OnGet()
        {
            AlwaysIn();
            AlwaysOut();
            if (ucnData.theRole != "teacher" && ucnData.theRole != "developer") return Redirect("/");
            return Page();
        }


        // Will also accept ChatGPT/CoPilot format
        //What is the main difference between IPv4 and IPv6?
        //
        //A) IPv4 uses 32-bit addresses, IPv6 uses 128-bit addresses
        //B) IPv4 supports multicast, IPv6 does not
        //C) IPv4 is used for local networks, IPv6 is used for the internet
        //D) IPv4 uses hexadecimal notation, IPv6 uses binary notation
        //E) IPv4 is faster than IPv6
        
        private void OnPostScan(string qText)
        {
            char[] delim = { '\r', '\n' };
            string[] myStrings = qText.Split(delim);
            int counter = 0;
            // Identify the Question part
            while (counter < myStrings.Length)
            {
                if (myStrings[counter] != "")
                {
                    questionCookie.QuestionText = myStrings[counter];
                    counter++;
                    break;
                }
                counter++;
            }
            if (counter >= myStrings.Length) return;
            // start from scratch
            questionCookie.AList.Clear();
            while (counter < myStrings.Length)
            {
                if (myStrings[counter] != "")
                {
                    string alt = myStrings[counter].Trim();
                    if (alt.Length > 3)
                        if (alt[1] == ')' || alt[1] == '.')
                            alt = alt.Remove(0, 3);
                    questionCookie.AList.Add(new Alternative
                    {
                        Atxt = alt,
                        Aok = false
                    });
                }
                counter++;
            }
            questionCookie.AList.Add(new Alternative
            {
                Atxt = "",
                Aok = false
            });
        }

        public IActionResult OnPost(string action = "NA", string tochange = "", string changeTo = "", string newCategory = "")
        {
            AlwaysIn();
            if (ucnData.theRole != "teacher" && ucnData.theRole != "developer") return Redirect("/");
            switch (action)
            {
                case "changeCategory":
                    questionCookie.Category = newCategory;
                    break;
                case "changeQText":
                    questionCookie.QuestionText = changeTo;
                    break;
                case "changeAText":
                    questionCookie.AList[int.Parse(tochange)].Atxt = changeTo;
                    if (int.Parse(tochange) == questionCookie.AList.Count - 1)
                    {
                        questionCookie.AList.Add(new Alternative
                        {
                            Atxt = "",
                            Aok = false
                        });
                    }
                    break;
                case "changeAOk":
                    // tochange: "0" changeTo: on
                    questionCookie.AList[int.Parse(tochange)].Aok = (changeTo == "on");
                    break;

                case "create":
                    qManager.InsertMCQuestion(questionCookie);
                    questionCookie.QuestionText = "";
                    questionCookie.QuestionID = "";
                    questionCookie.AList.Clear();
                    break;
                case "scan":
                    OnPostScan(tochange);
                    break;
                case "delete":
                    if (tochange != "") qManager.DeleteQuestion(tochange);
                    break;
                case "download":
                    Cat cat = qManager.GetCat(questionCookie.Category);
                    string output = qManager.ExportQuestionsEiken(questionCookie.Category);
                    string fileName = cat.Txt + "-Eiken.txt";
                    /* Not such good an idea. just keep as subjects */
                    /*
                    while (cat.CParentId != "/")
                    {
                        cat = qManager.GetCat(cat.CParentId);
                        fileName = cat.Txt + "-" + fileName;
                    }
                    */
                    var contentType = "text/plain";
                    var bytes = Encoding.UTF8.GetBytes(output);
                    var result = new FileContentResult(bytes, contentType);
                    result.FileDownloadName = fileName;
                    SetMyCookie();
                    return result;
                    break;
                case "upload": // https://www.learnrazorpages.com/razor-pages/forms/file-upload may benefit from async
                    if (Upload != null)
                    {
                        Stream myStream = Upload.OpenReadStream();
                        byte[] myBuffer = new byte[myStream.Length];
                        myStream.Position = 0;
                        myStream.Read(myBuffer, 0, myBuffer.Length);
                        myStream.Close();
                        EikenDecode(myBuffer);
                    }
                    break;
                default:
                    break;
            }
            CatMenu = qManager.MakeCList(UserID, "DropDown", questionCookie.Category);
            isSubmittable = questionCookie.AList.Where(x => x.Aok == true).Count() == 1 && questionCookie.Category != null;
            SetMyCookie();
            AlwaysOut();
            return Page();
        }
    }
}
