using REST_JSON_API;
using System.Collections;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

public class PopupBehavior : MonoBehaviour
{

    [SerializeField] GameObject canvas;
    [SerializeField] Button CloseButton;
    [SerializeField] TMP_Text message;
    public string MessageText
    {
        get => message.text;
        set => message.text = value;
    }

    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;

    #region UnityMethods

    void OnEnable()
    {
        ActiveScroll.OnMMTServerComunicationError.AddListener(OnShowErrorMessage);
        ActiveScroll.OnScrollDynamicInfoError.AddListener(OnFailedScrollInput);
        ActiveScroll.OnScrollApplicationError.AddListener(OnFailedScrollInput);
        ActiveScroll.OnCancelErrorState.AddListener(HidePopUp);
    }

    void OnDisable()
    {
        ActiveScroll.OnMMTServerComunicationError.RemoveListener(OnShowErrorMessage);
        ActiveScroll.OnScrollDynamicInfoError.RemoveListener(OnFailedScrollInput);
        ActiveScroll.OnScrollApplicationError.RemoveListener(OnFailedScrollInput);
        ActiveScroll.OnCancelErrorState.RemoveListener(HidePopUp);
    }
    
    void Awake()
    {
        CloseButton.onClick.RemoveAllListeners();
        CloseButton.onClick.AddListener(HidePopUp);

        HidePopUp();
    }
    #endregion UnityMethods

    public void ShowTimedPopUp()
    {
        canvas.SetActive(true);
        StartCoroutine(_BlossomAndDie());

        IEnumerator _BlossomAndDie()
        {
            yield return new WaitForSeconds(GlobalBehaviour.HintAnimationDuration);
            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(ScrollApplicationCheckingError[] errorInfo)
    {
        MessageText = generateHelpfulMessageAndAnimateScrollParam(errorInfo);
        ShowTimedPopUp();
    }
    /// <summary>
    /// this method gets an error message as parameter and shows it in a popup.
    /// </summary>
    /// <param name="errorMsg"></param>
    public void OnShowErrorMessage(string errorMsg)
    {
        MessageText = errorMsg;
        ShowTimedPopUp();
    }

    private string generateHelpfulMessageAndAnimateScrollParam(ScrollApplicationCheckingError[] errorInfo)
    {
        if (errorInfo == null)
            return ServerErrorMessage;

        int invAssCount = 0;
        errorMessage = "";
        for (int i = 0; i < errorInfo.Length; i++)
        {
            ScrollApplicationCheckingError error = errorInfo[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++;
                MMTFact fact = parseFactFromError(error);

                //animate all invalidly assigned facts
                if (ScrollDetails.ParameterDisplays != null && fact != null)
                {
                    foreach (RenderedScrollFact scrollfact in ScrollDetails.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 MMTFact parseFactFromError(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.Instance.Scroll.requiredFacts
            .Find(decl => decl.@ref.uri == error.fact.uri);
    }
}