using REST_JSON_API;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using TMPro;
using UnityEngine;

public class ScrollDetails : ScrollView
{
    public static ScrollDetails Instance
    {
        get => _Instance;
        set
        {
            if (_Instance != value)
                Destroy(_Instance);

            _Instance = value;
        }
    }
    private static ScrollDetails _Instance;

    public WorldCursor cursor;
    public GameObject parameterDisplayPrefab;
    public GameObject mmtAnswerPopUp;
    private PopupBehavior Popup;

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

    void Awake()
    {
        Instance = this;

        if (cursor == null) cursor = FindObjectOfType<WorldCursor>();

        Popup = mmtAnswerPopUp.GetComponent<PopupBehavior>();
        Popup.gameObject.SetActive(true); // force Awake
    }

    private void OnEnable()
    {
        SwitchScrollUI.activeScrollData.OnScrollChanged.AddListener(ShowScroll);
        SwitchScrollUI.activeScrollData.OnFactAssignmentUpdated.AddListener(OnFactAssignmentUpdated);
        SwitchScrollUI.activeScrollData.OnScrollDynamicInfoUpdated.AddListener(UpdateScrollDescription);
    }

    private void OnDisable()
    {
        SwitchScrollUI.activeScrollData.OnScrollChanged.RemoveListener(ShowScroll);
        SwitchScrollUI.activeScrollData.OnFactAssignmentUpdated.RemoveListener(OnFactAssignmentUpdated);
        SwitchScrollUI.activeScrollData.OnScrollDynamicInfoUpdated.RemoveListener(UpdateScrollDescription);
    }

    private void OnDestroy()
    {
        _Instance = null;
    }

    /// <summary>
    /// Update the scroll details screen to display the currently active scroll
    /// </summary>
    /// <param name="activeScroll"></param>
    private void ShowScroll(Scroll newScroll)
    {
        Transform originalScroll = gameObject.transform.GetChild(1);
        Transform originalScrollView = originalScroll.GetChild(1);
        Transform originalViewport = originalScrollView.GetChild(0);

        //Clear all current ScrollFacts
        originalViewport.GetChild(0).gameObject.DestroyAllChildren();

        var description = newScroll.description;
        // if description is a html description, extract the alternative text representation
        if (Regex.IsMatch(newScroll.description, ".*<scroll-description.*"))
        {
            description = Regex.Match(newScroll.description, "<scroll-description [^>]* alt=((?>\\\")|(?>\\'))([^>]*?)\\1[^>]*>").Groups[2].Value;
        }
        originalScroll.GetChild(0).GetComponent<TextMeshProUGUI>().text = description;

        //ParameterDisplays.ForEach(gameObj => Destroy(gameObj));
        ParameterDisplays = new();
        // generate parameter display slots
        foreach (var slot in SwitchScrollUI.activeScrollData.Assignments)
        {
            GameObject originalObj =
                Instantiate(parameterDisplayPrefab, originalViewport.GetChild(0));

            RenderedScrollFact originalRSF =
                originalObj.GetComponentInChildren<RenderedScrollFact>();

            ParameterDisplays.Add(originalRSF);

            originalRSF.Populate(newScroll, slot.Key);
            originalRSF.transform.parent.gameObject.SetActive(slot.Value.IsVisible);
        }
    }

    private void UpdateScrollDescription(Scroll rendered)
    {
        if (SwitchScrollUI.activeScrollData.DynamicScrollDescriptionsActive)
        { // Update scroll-description
            Transform scroll = gameObject.transform.GetChild(1).transform;
            scroll.GetChild(0).GetComponent<TextMeshProUGUI>().text = rendered.description;
        }
    }

    private void OnFactAssignmentUpdated(string slotUri, ActiveScroll.SlotAssignment slotAssignment)
    {
        RenderedScrollFact changed = ParameterDisplays.Find(RSF => RSF.ScrollFactURI == slotUri);

        // check if the RenderedScrollFact already contains the assigend fact
        // this is to prevent an endless loop because updating the Fact property will trigger the NewAssignmentEvent
        // TODO: BE: find an other solution beacause this results in requesting the scroll dynamic update twice from the server
        if (changed != null && (
            (!slotAssignment.IsSet && changed.IsSet) ||
            (slotAssignment.IsSet && changed.URI != slotAssignment.fact?.Id)
            ))
        {
            changed.Fact = slotAssignment.fact;
        }
    }
}