using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Events;

public class DialogueManager : MonoBehaviour
{
    [SerializeField]
    public string SpeakerName;

    [SerializeField]
    public LanguageDetector<MultiDialogue> languageDetector;

    /* We user object CLONED TO PREVENT overwritting changes in main object inassets */
    [SerializeField]
    public MultiDialogue Dialogue;

    // List<Key<dialogue No, dialogue step No>, Value : UnityEvent>
    public List<IndexValuePair<IndexValuePair<int, int>, UnityEvent>> EndactionEventList;

    [SerializeField] public KeyCode keyToOpen = KeyCode.E;

    public bool CanBeOpened = true;

    /// <summary>
    /// This flag tell that manager will open dialogue automatically after
    /// - beeing in collision range
    /// - when dialogue is closed
    /// - when Player press KeyToOpen button
    /// 
    /// Change var status in other sctipt if you want to use other triggers to open dialogue
    /// </summary>
    public bool OpenInDefaultWay = true;

    public virtual void Start()
    {
        Dialogue = Instantiate(languageDetector.DetectInstanceBasedOnLanguage());
        // Bind setted actions
        BindEndActionsToDialogues();

        // Add one more action
        Dialogue.Dialogues.ForEach(dial => dial.Value.SetActionAfterDialogueStep(dial.Key, dial.Value.ResetDialogue));  // reset dial 
        
        Dialogue.BuildCurrentDialogue();

        /*Debug.Log(Dialogue.DialogueStepStatus());
        Debug.Log(Dialogue
            .Dialogues
            .Where(dialogue => dialogue.Key == Dialogue.DialogueStepStatus().Item1)
            .First()
            .Value);

        Debug.Log(
            Dialogue
            .Dialogues
            .Where(dialogue => dialogue.Key == Dialogue.DialogueStepStatus().Item1)
            .First()
            .Value
            .DialogueSteps.Count());

        Debug.Log(
            Dialogue
            .Dialogues
            .Where(dialogue => dialogue.Key == Dialogue.DialogueStepStatus().Item1)
            .First()
            .Value
            .DialogueSteps
                .ElementAtOrDefault(Dialogue.DialogueStepStatus().Item2)
        );

        Debug.Log(
            Dialogue
            .Dialogues
            .Where(dialogue => dialogue.Key == Dialogue.DialogueStepStatus().Item1)
            .First()
            .Value
            .DialogueSteps
                .ElementAtOrDefault(Dialogue.DialogueStepStatus().Item2)
            .DialogueController
        );

        Debug.Log(
    Dialogue
    .Dialogues
    .Where(dialogue => dialogue.Key == Dialogue.DialogueStepStatus().Item1)
    .First()
    .Value
    .DialogueSteps
        .ElementAtOrDefault(Dialogue.DialogueStepStatus().Item2)
    .DialogueController
    .listOfDialogue.Count()
);

        Debug.Log(GetCurrentDialoguePanelStatus());*/
    }


    public void Update()
    {
        if (OpenInDefaultWay && Input.GetKeyDown(keyToOpen) && OpenPanelCondition())
        {
            OpenDialoguePanel();
        }
    }


    public virtual void OnTriggerEnter2D(Collider2D collision)
    {
        // don't listen when component is disabled
        if (ComponentEnabledCondition())
            return;

        if (collision.gameObject.tag == "Player")
        {
            CanBeOpened = true;

            SpeakerName = collision.gameObject.name;
        }
    }
    public virtual void OnTriggerExit2D(Collider2D collision)
    {
        // don't listen when component is disabled
        if (ComponentEnabledCondition() || !OpenInDefaultWay)
            return;

        if (collision.gameObject.tag == "Player")
        {
            CanBeOpened = false;

            if (GetCurrentDialoguePanelStatus())
            {
                Dialogue.BreakDialogueStep();
            }
        }
    }

    public void OpenDialoguePanel()
    {
        if(OpenPanelCondition())
        {
            // Update speaker name before every opening
            Dialogue.SetSpeakerName(SpeakerName);

            gameObject.GetComponent<DialogueManager>().Dialogue.StartDialogue();
        }
    }
    public virtual bool OpenPanelCondition()
    {
        /*
         * Conditions:
         * - player is in collision range
         * - panel assigned to next sentence in dialogue must be closed 
         */
        return IsInRangeCondition() && !GetCurrentDialoguePanelStatus();
    }

    public bool IsInRangeCondition()
    {
        return CanBeOpened;
    }

    protected virtual bool ComponentEnabledCondition()
    {
        return !gameObject.GetComponent<DialogueManager>().enabled;
    }

    /// <summary>
    /// Opened = 1
    /// Closed = 0
    /// </summary>
    /// <returns></returns>
    public bool GetCurrentDialoguePanelStatus()
    {
        Debug.Log(Dialogue);
        var multiDialStatius = Dialogue.DialogueStepStatus();
        Debug.Log(multiDialStatius);

        Debug.Log(Dialogue
            .Dialogues
            .Where(dialogue => dialogue.Key == multiDialStatius.Item1)
            .First()
            .Value
            .DialogueSteps);
            
        return Dialogue
            .Dialogues
            .Where(dialogue => dialogue.Key == multiDialStatius.Item1)
            .First()
            .Value
            .DialogueSteps
            .ElementAtOrDefault(multiDialStatius.Item2)
            ?.DialogueController.CurrentPanel != null;
    }

    public void BindEndActionsToDialogues()
    {
        foreach(var finalAction in EndactionEventList)
        {
            // finalAction.Key.Key | .Value/
            Dialogue
                 .Dialogues
                 .Where(dial => dial.Key == finalAction.Key.Key)
                 .FirstOrDefault()
                 .Value
                 .DialogueSteps
                 .ElementAtOrDefault(finalAction.Key.Value)
                 .SetActionAfterDialogueStep(finalAction.Value)
            ;
        }
    }
}