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 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)
    {
        if (Dialogues.Where(el => el.Key == dialogueNumber).ToArray().Count() == 0)
            return;

        // 1. Make sure to close current panel after finishing current dialogue and 'finish action' will invoked if setuped
        Dialogues.Where(el => el.Key == CurrentDialogue).ToArray().First().Value.FinishDialogue();

        // 2. Chane index
        CurrentDialogue = dialogueNumber;
    }

    public void SetNextDialogueWithoutFinalAction(int dialogueNumber)
    {
        if (Dialogues.Where(el => el.Key == dialogueNumber).ToArray().Count() == 0)
            return;

        // 1. Make sure to close current panel after finishing current dialogue and 'finish action' will invoked if setuped
        Dialogues.Where(el => el.Key == CurrentDialogue).ToArray().First().Value.CloseDialogue();

        // 2. Chane index
        CurrentDialogue = dialogueNumber;
    }

    /// <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. Update proggress
        // Savintg one more time because saving in final action invoking by line above
        // dont contain increased 'CurrentDialogue' index pointer !!!
        //((MultiDialogueDataManager)MultiDialogueDataManager.Instance).RegisterDialogue(this);

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

    /// <summary>
    /// Function like one above but
    /// PREFPARED AS FINAL ACTION IN DIALOGUE WHICH IS INVOKED VIA 'Dialogue.FinishDialoge'
    /// to prevent looping Final aCTION INVOKING
    ///     once from 'Dialogue.FinishDialoge' in button next time from 'MultiDialogue.SetNextDialogue -> FinishDialogue' ....
    /// </summary>
    /// <param name="dialogueNumber"></param>
    public void GoToNextDialogueWithoutFinalAction(int dialogueNumber)
    {
        // 1. Prepare necessary environoment parts
        SetNextDialogueWithoutFinalAction(dialogueNumber);

        // 2. Update proggress
        //((MultiDialogueDataManager)MultiDialogueDataManager.Instance).RegisterDialogue(this);


        // 3. 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()
    {
        SpeakerName = "";
        CurrentDialogue = 0;

        Dialogues.ForEach(dial => dial.Value.SetSpeakerName(""));
        Dialogues.ForEach(dial => dial.Value.CurrentStep = 0);
        Dialogues.ForEach(dial => dial.Value.DialogueSteps.ForEach(step => step.WasDisplayed = false));
    }

    public (int, int) DialogueStepStatus()
    {
/*        var currentStep = Dialogues
            .Where(el => el.Key == CurrentDialogue)
            .Select(el => el.Value)
            .First()
            .CurrentStep
        ;*/

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

        return(CurrentDialogue, currentDialogueStepIndex); 
    }
}