using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using UnityEngine.UI;
using System.Linq;
using static SOMDocManager;

public class PopupBehavior : MonoBehaviour
{

    [SerializeField] GameObject canvas;
    [SerializeField] Button CloseButton;
    [SerializeField] TMP_Text message;

    public Scroll ActiveScroll { private get; set; }
    public List<RenderedScrollFact> ParameterDisplays { private get; set; }

    public string ServerErrorMessage = "unknown server error";
    public string NonTotalMessage = "Scroll application not complete";
    public string UnknownErrorMessage = "Unkown error - did you apply all facts?";
    public string InvalidAssignmentMessage = "Invalid Assignment";

    private string errorMessage = "";
    // Start is called before the first frame update
    void Awake()
    {
        CommunicationEvents.PushoutFactFailEvent.AddListener(onFailedScrollInput);

        CloseButton.onClick.RemoveAllListeners();
        CloseButton.onClick.AddListener(hidePopUp);
    }

    public void setMessage(string errorMessage)
    {
        this.message.text = errorMessage;
    }

    public void showPopUp()
    {
        canvas.SetActive(true);
        StartCoroutine(hideAfter5sec());

        IEnumerator hideAfter5sec()
        {
            yield return new WaitForSeconds(5);
            hidePopUp();
        }
    }

    public void hidePopUp()
    {
        canvas.SetActive(false);
    }

    /// <summary>
    /// this method creates a helpful error message and shows the popup. For it to work properly, the setScroll and setParameterDisplays must have been set.
    /// </summary>
    /// <param name="startfact"></param>
    /// <param name="errorInfo"></param>
    public void onFailedScrollInput(Fact startfact, Scroll.ScrollApplicationInfo errorInfo)
    {
        setMessage(generateHelpfulMessageAndAnimateScrollParam(errorInfo));
        showPopUp();
    }

    private string generateHelpfulMessageAndAnimateScrollParam(Scroll.ScrollApplicationInfo errorInfo)
    {
        if (errorInfo == null)
            return ServerErrorMessage;

        int invAssCount = 0;
        errorMessage = "";
        for (int i = 0; i < errorInfo.errors.Length; i++)
        {
            Scroll.ScrollApplicationCheckingError error = errorInfo.errors[i];

            //check which error ocurred and set Message to a helpful error message.
            if (error.kind == "nonTotal")
            {
                errorMessage += NonTotalMessage;
                errorMessage += '\n';
            }
            else if (error.kind == "invalidAssignment")
            {
                invAssCount++;
                MMTDeclaration fact = parseFactFromError(error);

                //animate all invalidly assigned facts
                if (ParameterDisplays != null && fact != null)
                {
                    foreach (RenderedScrollFact scrollfact in ParameterDisplays)
                        if (scrollfact.ScrollFactURI == fact.@ref.uri)
                            scrollfact.HighlightAs(FactWrapper.FactMaterials.Hint);
                }
                else
                {
                    Debug.Log("PopupBehavior: Error: scroll or parameterDisplays not set.");
                }
            }
            else if (error.kind == "unknown")
            {
                errorMessage += UnknownErrorMessage;
                errorMessage += '\n';
            }
        }

        //invalid assignment message
        if (invAssCount > 0)
        {
            errorMessage += invAssCount.ToString() + " " + InvalidAssignmentMessage;
            if (invAssCount > 1) //plural for invalid assignments
            {
                errorMessage += 's';
            }
            errorMessage += '\n';
        }

        return errorMessage;
    }

    //this should be changed, the Fact Object should be parsed by JSON. This is a workaround because the MMT servers JSON serialization contains a bug
    private MMTDeclaration parseFactFromError(Scroll.ScrollApplicationCheckingError error)
    {
        if (error == null || error.msg == null)
            return null;
        
        string message = error.msg;

        //cut start of string
        int indexFact = message.IndexOf('[');
        string factUri = message.Substring(indexFact + 1);

        // cut end of string
        int indexFactEnd = factUri.IndexOf(']');
        string rest = factUri.Substring(indexFactEnd);
        factUri = factUri.Substring(0, indexFactEnd);

        //get fact Label from the rest of the string
        int factNameLength = rest.IndexOf('?') - 2;
        string factLabel = rest.Substring(2, factNameLength);

        //add ?factName to URI
        factUri += "?" + factLabel;

        //find the required fact in the active scroll thats invalidly assigned
        return ActiveScroll?.requiredFacts
            .FirstOrDefault(decl => decl.@ref.uri.Equals(factUri));
    }
}