using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

[Serializable]
[CreateAssetMenu(fileName = "New Dialogue", menuName = "Dialogue/New Multi Dialogue")]
public class MultiDialogue : ScriptableObject, IDialogue
{
    [SerializeField]
    public string SpeakerName;

    [SerializeField]
    public int CurrentDialogue = 0;

    [SerializeField]
    public List<IndexValuePair<int, Dialogue>> Dialogues;


    /*
        Dialogues - list of dialoges
           Steps bucket (one dialogue unit) - list of liner 'steps', finished special action, whole can be stopped special requirements (like go and do something - to declared in 'finish action')
                Steps - its a cell package contains 'sentences' (one per panel)
                    Sentence - its a opanel with phrase and buttons
    */

    /*
     * WAZNE:
     *      Jesli przechodzimy odpowiedzia do nastepnego dialogu musi to byc osttani panel w obecnym!!!
     */

    public void Start()
    {
        /*      CODE DIALOGUE DECLARATION EXAMPLE  

            DialogueController DialogueStep = new DialogueController();
            DialogueStep.AddSentence(new DialogueModel("lorem ipsum"));
            *//*        di.AddSentence(new QuestionDialogueModel("tolore dolore?",
                        new List<Tuple<string, Action>> {
                            new Tuple<string, Action>("AcceptButton", CustomPanel),
                            new Tuple<string, Action>("RejectButton", QuestionPanel)
                        }));*//*
            DialogueStep.SetActionAfterDialogueEnds(() => { });

            DialogueStepModel dialogueStepModel = new DialogueStepModel(DialogueStep);

            DialogueStepsList = new List<DialogueStepModel> { dialogueStepModel };
        */
        /*if (MultiWayDialogue.Count > 0)
            BuildDialogue(MultiWayDialogue.Where(el => el.Key == CurrentDialogue).First().Value);*/
    }

    public void SetSpeakerName(string speakerName)
    {
        SpeakerName = speakerName;

        Dialogues.ForEach(dialogue => dialogue.Value.SetSpeakerName(speakerName));
    }

    public void StartDialogue()
    {
        // 1. Start Dialogue (build + show panel)
        Dialogues.Where(el => el.Key == CurrentDialogue).First().Value.StartDialogue();
    }

    public void BreakDialogueStep()
    {
        // 1. Break Dialogue (close panel without marking as displayed)
        Dialogues.Where(el => el.Key == CurrentDialogue).ToArray().First().Value.BreakDialogueStep();
    }

    /// <summary>
    /// Dialogue API
    /// 
    /// MAIN bunction to begin dialogue 
    /// Create new panel instance on scene by force with sentence from queue
    /// 
    /// The best way is to invoked its after player reaction from other script (by event - collision) :)
    /// </summary>
    public void ShowDialogueStepPanel()
    {
        Dialogues.Where(el => el.Key == CurrentDialogue).ToArray().First().Value.ShowDialogueStepPanel();
    }

    /// <summary>
    /// Dialogue API
    /// 
    /// Default function to get next sentence if dialogue is currently started
    /// It is responsible for detecting 
    ///   1) if there is any dialogue panel already created before displaying next sentence
    ///   2) if its last panel sentence and invoiking 'end dialogue' action
    ///   
    /// Whats more, if there was no more sentences in 'step', althroughr closing panel go to next step automatiiccally 
    /// </summary>
    public void GoToNextSentence()
    {
        Dialogues.Where(el => el.Key == CurrentDialogue).ToArray().First().Value.GoToNextSentence();
    }

    /// <summary>
    /// Dialogue API
    /// 
    /// Function to prepare next dialogue to start after one more palyer interaction with actor
    ///  - ends current dialogue (destroy panel & invoke finish action - if setupped)
    ///  - set new dialogue pointer
    ///  
    /// </summary>
    /// <param name="dialogueNumber"></param>
    public void SetNextDialogue(int dialogueNumber)
    {
        Debug.Log("----------------- SetNextDialogue");
        Debug.Log(dialogueNumber);
        if (Dialogues.Where(el => el.Key == dialogueNumber).ToArray().Count() == 0)
            return;

        // 2. Chane index
        CurrentDialogue = dialogueNumber;

        // 1. Make sure to close current panel after finishing current dialogue and 'finish action' will invoked if setuped
        GoToNextSentence();
    }

    /// <summary>
    /// Dialogue API
    /// 
    /// Function to finish current dialog and immediately start next one
    /// 
    /// </summary>
    /// <param name="dialogueNumber"></param>
    public void GoToNextDialogue(int dialogueNumber)
    {
        // 1. Prepare necessary environoment parts
        SetNextDialogue(dialogueNumber);

        // 2. Build new (next) dialogue & show panel
        StartDialogue();
    }

    // MUST BE IMPLEMENTED - INTERFACE RULES
    // USELESS IN THIS FILE
    public void BuildDialogue(List<DialogueStepModel> Dialogue)
    {
        foreach (var dialogueStep in Dialogue)
        {
            dialogueStep.Header = SpeakerName;

            dialogueStep.Build();
        }
    }


    /// <summary>
    /// Build each step of dialogue
    /// </summary>
    public void BuildDialogue(Dialogue Dialogue)
    {
        Dialogue.SetSpeakerName(SpeakerName);
        Dialogue.BuildDialogue();
    }

    public void BuildCurrentDialogue()
    {
        BuildDialogue(Dialogues.Where(dial => dial.Key == CurrentDialogue).ToArray().First().Value);
    }

    /// <summary>
    /// Function to reset rememebered dialogue status
    /// 
    /// (Scriptable objects clones are overwritten during clone modification)
    /// </summary>
    public void ResetDialogue()
    {
        Dialogues.ForEach(dial => dial.Value.DialogueSteps.ForEach(step => step.WasDisplayed = false));
    }

    public (int, int) DialogueStepStatus()
    {
        var currentDialogueStepIndex = Dialogues
            .Where(el => el.Key == CurrentDialogue)
            .Select(el => el.Value)
            .First()
            .DialogueSteps
            .Where(step => step.WasDisplayed == true)
            .ToArray()
            .Count()
        ;

        return(CurrentDialogue, currentDialogueStepIndex); 
    }
}