using System;
using System.Collections.Generic;
#if !NET8
using System.Web;
using System.Web.Mvc;
#endif

#if NET8
using Microsoft.AspNetCore.Mvc;
#endif

using Fab2ApprovalSystem.DMO;
using Fab2ApprovalSystem.Misc;
using Fab2ApprovalSystem.Models;
using Fab2ApprovalSystem.Utilities;

#if !NET8
using System.Configuration;
using System.Linq;
using Fab2ApprovalSystem.ViewModels;
#endif

#if !NET8
using Kendo.Mvc.Extensions;
using Kendo.Mvc.UI;
#endif

namespace Fab2ApprovalSystem.Controllers;

#if !NET8
[Authorize]
#if !NET8
[SessionExpireFilter]
#endif
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
#endif
#if NET8
[Route("[controller]")]
#endif
public class HomeController : Controller {

    private readonly MRB_DMO mrbDMO = new(GlobalVars.AppSettings);
    private readonly PartsRequestDMO prDMO = new();
    private readonly LotDispositionDMO ldDMO = new();
    private readonly WorkflowDMO wfDMO = new();
    private readonly ECN_DMO ecnDMO = new();
    private readonly UserUtilities userDMO = new();
    private readonly UserAccountDMO originalUserDMO = new();
    private readonly TrainingDMO trainingDMO = new();
    private readonly MiscDMO miscDMO = new();
    private readonly AppSettings _AppSettings = GlobalVars.AppSettings;

    public ActionResult Index(string tabName) {
        ViewBag.ActiveTabName = tabName;

        return View();
    }

    public ActionResult MyTasks() {
        return View();
    }

    public ActionResult AllDocuments() {
        return View();
    }

    public ActionResult SpecialWorkRequestList() {
        return View();
    }

    public ActionResult MRBList() {
        return View();
    }

    public ActionResult ECNList() {
        return View();
    }

    public ActionResult TrainingList() {
        return View();
    }

    public ActionResult LotDispositionList() {
        return View();
    }

    public ActionResult AuditList() {
        return View();
    }

    public ActionResult CorrectiveActionList() {
        return View();
    }

    public ActionResult ECN_TECN(string viewOption) {
        ViewBag.ViewOption = viewOption;
        return View();
    }

    public ActionResult ChangeControlList() {
        return View();
    }

#if !NET8

    public ActionResult GetTaskList([DataSourceRequest] DataSourceRequest request, string tabName) {
        try {
            ViewBag.ActiveTabName = tabName;
            List<IssuesViewModel> data = ldDMO.GetTaskList(GlobalVars.GetUserId(GetSession())).Distinct().ToList();
            return GetJsonResult(data.ToDataSourceResult(request));
        } catch (Exception ex) {
            throw;
        }
    }

    public ActionResult GetMyOpenActionItems([DataSourceRequest] DataSourceRequest request, string tabName) {
        try {
            ViewBag.ActiveTabName = tabName;
            List<OpenActionItemViewModel> data = ldDMO.GetMyOpenActionItems(GlobalVars.GetUserId(GetSession())).Distinct().ToList();
            return GetJsonResult(data.ToDataSourceResult(request));
        } catch (Exception ex) {
            throw;
        }
    }

    public ActionResult GetDocuments([DataSourceRequest] DataSourceRequest request, string tabName) {
        ViewBag.ActiveTabName = tabName;
        IEnumerable<IssuesViewModel> data = ldDMO.GetDocuments();
        return Json(data.ToDataSourceResult(request));
    }

    public ActionResult GetWorkRequests([DataSourceRequest] DataSourceRequest request) {
        IEnumerable<IssuesViewModel> data = ldDMO.GetWorkRequests();
        return Json(data.ToDataSourceResult(request));
    }

    public ActionResult GetChangeControlList([DataSourceRequest] DataSourceRequest request) {
        IEnumerable<ChangeControlList> data = ldDMO.GetChangeControls(GlobalVars.GetUserId(GetSession()));
        return Json(data.ToDataSourceResult(request));
    }

    public ActionResult GetAuditList([DataSourceRequest] DataSourceRequest request) {
        IEnumerable<AuditList> data = ldDMO.GetAuditList(GlobalVars.GetUserId(GetSession()));
        return Json(data.ToDataSourceResult(request));
    }

    public ActionResult GetCorrectiveActionList([DataSourceRequest] DataSourceRequest request) {
        IEnumerable<CorrectiveAction> data = ldDMO.GetCorrectiveActionList(GlobalVars.GetUserId(GetSession()));
        return Json(data.ToDataSourceResult(request));
    }

    public ActionResult GetMRBList([DataSourceRequest] DataSourceRequest request) {
        IEnumerable<IssuesViewModel> data = ldDMO.GetMRBList(GlobalVars.GetUserId(GetSession()));
        return Json(data.ToDataSourceResult(request));
    }

    public ActionResult GetLotDispositionList([DataSourceRequest] DataSourceRequest request) {
        IEnumerable<IssuesViewModel> data = ldDMO.GetLotDispositionList(GlobalVars.GetUserId(GetSession()));
        return Json(data.ToDataSourceResult(request));
    }

    public ActionResult GetECNList([DataSourceRequest] DataSourceRequest request) {
        IEnumerable<IssuesViewModel> data = ldDMO.GetECNList(GlobalVars.GetUserId(GetSession()));
        return Json(data.ToDataSourceResult(request));
    }

    public ActionResult GetTrainingList([DataSourceRequest] DataSourceRequest request) {
        IEnumerable<Training> data = trainingDMO.GetAllTrainings();
        return Json(data.ToDataSourceResult(request));
    }

#endif

    public ActionResult MyECNsTECNs(string dataType) {
        ViewBag.ActiveTabName = dataType;
        return View();
    }

#if !NET8

    public ActionResult GetECN_TECNsPendingApproval([DataSourceRequest] DataSourceRequest request) {
        IEnumerable<IssuesViewModel> data = ecnDMO.GetECN_TECNPendingApprovals(GlobalVars.GetUserId(GetSession()));
        ViewBag.ViewOption = "Pending Approvals";
        GlobalVars.SetECNViewOption(GetSession(), ViewBag.ViewOption);
        return Json(data.ToDataSourceResult(request));
    }

    public ActionResult GetMyExpiredTECNs([DataSourceRequest] DataSourceRequest request) {

        IEnumerable<IssuesViewModel> data = ecnDMO.GetMyExpiredTECNs(GlobalVars.GetUserId(GetSession()), 7);
        ViewBag.ViewOption = "Expired TECNs";
        GlobalVars.SetECNViewOption(GetSession(), ViewBag.ViewOption);
        return Json(data.ToDataSourceResult(request));
    }

    public ActionResult GetAllTECNs([DataSourceRequest] DataSourceRequest request) {
        IEnumerable<IssuesViewModel> data = ecnDMO.GetAllTECNs();
        ViewBag.ViewOption = "All TECNs";
        GlobalVars.SetECNViewOption(GetSession(), ViewBag.ViewOption);
        return Json(data.ToDataSourceResult(request));
    }

    public ActionResult GetMyConvertedTECNsToECNs([DataSourceRequest] DataSourceRequest request) {
        IEnumerable<IssuesViewModel> data = ecnDMO.GetMyConvertedTECNsToECNs(GlobalVars.GetUserId(GetSession()), 7);
        ViewBag.ViewOption = "Converted TECNs";
        GlobalVars.SetECNViewOption(GetSession(), ViewBag.ViewOption);
        return Json(data.ToDataSourceResult(request));
    }

    public ActionResult GetMyExpiringTECNs([DataSourceRequest] DataSourceRequest request) {
        IEnumerable<IssuesViewModel> data = ecnDMO.GetMyExpiringTECNs(GlobalVars.GetUserId(GetSession()), 7);
        ViewBag.ViewOption = "Expiring TECNs";
        GlobalVars.SetECNViewOption(GetSession(), ViewBag.ViewOption);
        return Json(data.ToDataSourceResult(request));
    }

    public ActionResult GetLotList([DataSourceRequest] DataSourceRequest request, int workRequestID) {
        LotTravelerDMO LotTravDMO = new LotTravelerDMO();
        return Json(LotTravDMO.GetLotListBasedOnSWRNumber(workRequestID).ToDataSourceResult(request));
    }

#endif

    public ActionResult SetOOOStatus(int delegatedTo, DateTime startDate, DateTime endDate, string tab) {
        if (GlobalVars.IsUserIdValueNotNull(GetSession())) {
            int returnValue = MiscDMO.EnableOOOStatus(GlobalVars.GetUserId(GetSession()), delegatedTo, startDate, endDate);
            if (returnValue == 3) // the delegator is already a delegator to someone else
            {
                return Content("3");
            }
            if (startDate <= DateTime.Today)
                GlobalVars.SetOOO(GetSession(), true);

            NotifyDelegation(delegatedTo, startDate, endDate);
        }

        return Content("");
    }

    public void ExpireOOOStatus(string tab) {
        if (GlobalVars.IsUserIdValueNotNull(GetSession())) {
            MiscDMO.ExpireOOOStatus(GlobalVars.GetUserId(GetSession()));
            GlobalVars.SetOOO(GetSession(), false);
        }
    }

#if !NET8

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult DeleteItem([DataSourceRequest] DataSourceRequest request, IssuesViewModel issue) {
        GlobalVars.DocumentType dType;
        Enum.TryParse(issue.DocumentType, out dType);
        if (dType == GlobalVars.DocumentType.MRB)
            mrbDMO.DeleteMRB(issue.IssueID);
        else if (dType == GlobalVars.DocumentType.LotDisposition)
            ldDMO.DeleteLotDisposition(issue.IssueID);
        else if (dType == GlobalVars.DocumentType.ECN)
            ecnDMO.DeleteDocument(issue.IssueID, GlobalVars.GetUserId(GetSession()), "ECN");
        else if (dType == GlobalVars.DocumentType.CorrectiveAction)
            ldDMO.DeleteCADocument(issue.IssueID, GlobalVars.GetUserId(GetSession()), "Corrective Action");

        return Json(new[] { issue }.ToDataSourceResult(request, ModelState));
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult DeleteCAItem([DataSourceRequest] DataSourceRequest request, CorrectiveAction ca) {
        ldDMO.DeleteCADocument(ca.CANo, GlobalVars.GetUserId(GetSession()), "Corrective Action");

        return Json(new[] { ca }.ToDataSourceResult(request, ModelState));
    }

#endif

    public ActionResult About() {
        ViewBag.Message = "Your application description page.";

        return View();
    }

    public ActionResult Contact() {
        ViewBag.Message = "Your contact page.";

        return View();
    }

    #region testing purpose
    public ActionResult Edit() {
        return View(DemoHelper.Instance.ListOfModels[0]);
    }

    [HttpPost]
    public ActionResult Edit(TestModel editTest) {
        DemoHelper.Instance.ListOfModels[0] = editTest;
        return RedirectToAction("Index");
    }

    public static void Test() {
        string[] colorStrings = { "0", "2", "8", "blue", "Blue", "Yellow", "Red, Green" };
        foreach (string colorString in colorStrings) {
            GlobalVars.Colors colorValue;
            if (Enum.TryParse(colorString, true, out colorValue))
                if (Enum.IsDefined(typeof(GlobalVars.Colors), colorValue) | colorValue.ToString().Contains(","))
                    Console.WriteLine("Converted '{0}' to {1}.", colorString, colorValue.ToString());
                else
                    Console.WriteLine("{0} is not an underlying value of the Colors enumeration.", colorString);
            else
                Console.WriteLine("{0} is not a member of the Colors enumeration.", colorString);
        }
    }

    #endregion

    public void DelegateDocumentApproval(int issueID, int delegateTo, string ecnTypeString, string title) {
        var email = "";
        int delegateFrom = GlobalVars.GetUserId(GetSession());
        try {
            email = wfDMO.DelegateDocumentApproval(issueID, delegateFrom, delegateTo);
            EventLogDMO.Add(new WinEventLog() { IssueID = issueID, UserID = GetUserIdentityName(), DocumentType = ecnTypeString, OperationType = "Delegation", Comments = "Delegated from - " + delegateFrom + " to " + delegateTo });
        } catch (Exception e) {
            string exceptionString = e.Message.ToString().Trim().Length > 500 ? "Issue=" + issueID.ToString() + " " + e.Message.ToString().Substring(0, 250) : e.Message.ToString();
            Functions.WriteEvent(_AppSettings, GetUserIdentityName() + "\r\n DelegateApproval\r\n" + e.Message.ToString(), System.Diagnostics.EventLogEntryType.Error);
            EventLogDMO.Add(new WinEventLog() { IssueID = issueID, UserID = GetUserIdentityName(), DocumentType = " + ecnTypeString + ", OperationType = "Error", Comments = "DelegateApproval - " + exceptionString });
            throw new Exception(e.Message);
        }
        HomeHelper.DelegateDocumentApproval(_AppSettings, issueID, ecnTypeString, title, email);
        try {
            EventLogDMO.Add(new WinEventLog() { IssueID = issueID, UserID = GetUserIdentityName(), DocumentType = ecnTypeString, OperationType = "Email", Comments = "Delegated to Approver: " + email });
        } catch { }
    }

    public JsonResult GetAllUsersList() {

        UserAccountDMO userDMO = new();
        IEnumerable<LoginModel> userlist = userDMO.GetAllUsers();
        return GetJsonResult(userlist);
    }

    public ActionResult SaveAllDocumentsFilter(string data) {
        GlobalVars.SetAllDocumentsFilterData(GetSession(), data);
        return new EmptyResult();
    }

    public ActionResult LoadAllDocumentsFilter() {
        return GetJsonResult(GlobalVars.GetAllDocumentsFilterData(GetSession()));
    }

    public ActionResult SaveSWRFilter(string data) {
        GlobalVars.SetSWRFilterData(GetSession(), data);
        return new EmptyResult();
    }

    public ActionResult LoadSWRFilter() {
        return GetJsonResult(GlobalVars.GetSWRFilterData(GetSession()));
    }

    public ActionResult SavePCRBFilter(string data) {
        GlobalVars.SetPCRBFilterData(GetSession(), data);
        return new EmptyResult();
    }

    public ActionResult LoadPCRBFilter() {
        return GetJsonResult(GlobalVars.GetPCRBFilterData(GetSession()));
    }

    public ActionResult PartsRequestList() {
        ViewBag.CanDeletePR = GlobalVars.GetCanCreatePartsRequest(GetSession());
        return View();
    }

#if !NET8

    public ActionResult GetPartsRequestList([DataSourceRequest] DataSourceRequest request) {
        IEnumerable<PartsRequestList> data = prDMO.GetPartsRequestList();
        return Json(data.ToDataSourceResult(request));
    }

    public ActionResult GetMyPartsRequestsList([DataSourceRequest] DataSourceRequest request, string tabName) {
        try {
            ViewBag.ActiveTabName = tabName;
            var data = prDMO.GetMyPartsRequests(GlobalVars.GetUserId(GetSession()));
            return GetJsonResult(data.ToDataSourceResult(request));
        } catch (Exception ex) {
            throw;
        }
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult DeletePR([DataSourceRequest] DataSourceRequest request, MyPartsRequestList pr) {
        try {
            if (!GlobalVars.GetCanCreatePartsRequest(GetSession()))
                throw new Exception("Permission denied");

            prDMO.DeleteDocument(pr.PRNumber, GlobalVars.GetUserId(GetSession()));
            return Json(new[] { pr }.ToDataSourceResult(request, ModelState));
        } catch (Exception ex) {
            return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest, ex.Message);
        }
    }

#endif

    public void NotifyDelegation(int delegatedUser, DateTime startDate, DateTime endDate) {
        LoginModel delegateFrom = originalUserDMO.GetUserByID(GlobalVars.GetUserId(GetSession()));
        LoginModel delegateTo = originalUserDMO.GetUserByID(delegatedUser);
        List<string> emailList = new();
        emailList.Add(delegateFrom.Email);
        emailList.Add(delegateTo.Email);
        HomeHelper.NotifyDelegation(_AppSettings, startDate, endDate, delegateFrom, delegateTo, emailList);
        try {
        } catch { }
    }

    public bool ProcessOoO() {

        try {
            UserAccountDMO userDMO = new();
            userDMO.ProcessOoO();
            return true;
        } catch {
            return false;
        }
    }

    public bool ExpireOoO() {
        try {
            UserAccountDMO userDMO = new();
            userDMO.ExpireOoO();
            return true;
        } catch {
            return false;
        }
    }

    public bool ApprovalsReminderNotifications() {
        try {
            // Get list of approvals
            List<ApproveListModel> approveList = miscDMO.GetApprovalReminderList();

            foreach (var item in approveList) {
                try {
                    NotifyApprover(item.AssignedEmail, item.Title, item.IssueID, item.DocType);
                } catch (Exception e) {
                    EventLogDMO.Add(new WinEventLog() { IssueID = item.ApprovalKey, UserID = "SYSTEM", DocumentType = "Approval Reminders", OperationType = "Email", Comments = e.Message });
                }
                // We want to update the last notification anyway so we don't continue trying on something that may be failing.
                miscDMO.UpdateApprovalNotifyDate(item.ApprovalKey);
            }
            // List<ApproveListModel> approveList = miscDMO.
            return true;
        } catch {
            return false;
        }
    }

    public void NotifyApprover(string toEmail, string title, int issueId, string docType) {
        try {
            HomeHelper.NotifyApprover(_AppSettings, toEmail, title, issueId, docType);

            try {
                EventLogDMO.Add(new WinEventLog() { IssueID = issueId, UserID = GetUserIdentityName(), DocumentType = docType, OperationType = "Email", Comments = "Approval reminders" });
            } catch { }

        } catch (Exception e) {
            string detailedException = "";
            try {
                detailedException = e.InnerException.ToString();
            } catch {
                detailedException = e.Message;
            }
            EventLogDMO.Add(new WinEventLog() { IssueID = issueId, UserID = GetUserIdentityName(), DocumentType = docType, OperationType = "Email", Comments = "Approval reminders" });
            throw;
        }
    }

#if !NET8

    private System.Web.HttpSessionStateBase GetSession() =>
        Session;

    private JsonResult GetJsonResult(object? data) =>
        Json(data, JsonRequestBehavior.AllowGet);

    private bool IsAjaxRequest() =>
        Request.IsAjaxRequest();

#endif

#if NET8

    private Microsoft.AspNetCore.Http.ISession GetSession() =>
        HttpContext.Session;

    private JsonResult GetJsonResult(object? data) =>
        Json(data);

    private bool IsAjaxRequest() =>
        Request.Headers.TryGetValue("X-Requested-With", out Microsoft.Extensions.Primitives.StringValues strings) && strings[0] == "XMLHttpRequest";

#endif

    private string GetUserIdentityName() =>
        @User.Identity.Name;

}