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


[Serializable]
[CreateAssetMenu(fileName = "New Mission", menuName = "Mission/New Mission")]

public class Mission : ScriptableObject
{
    [SerializeField]
    public string MissionName;

    [SerializeField]
    public Task PlayerTask;

    [SerializeField]
    public string SpeakerName;


    /*    [SerializeField]
        public MissionTypeEnum Type;*/

    [SerializeField]
    public MissionStatusEnum Status = MissionStatusEnum.None;

    [SerializeField]
    public int CurrentStep = 0;

    [SerializeField]
    public List<MissionStepModel> MissionStepsList;
    /*
        [SerializeField]
        public MissionProcess missionProcess = null;*/

    [SerializeField]
    public MissionReward Reward;

    //ConditionController . check condition
    //private ConditionFactory factory = new ConditionFactory();

    /*    
        public void AssignMissionProcessToStep(int stepNumber)
        {
            MissionStepsList[stepNumber].SetStepProcess(missionProcess);
        }
    */

    /*    public void SetMissionCondition(string name)
        {
            //factory.CreateCondition(Type); //, name)
        }*/

    // Set by hand as mission condition as final astion specyfic step
    public void CheckMissionRequirements()
    {

    }

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


    public void Accept()
    {
        Debug.Log("Accepting mission");

        Status = MissionStatusEnum.Accepted;

        // ADD CONDITION LISTENING TO SPECIFY MISSION MANAGER missions list

        CreateQuestOnList();

        //// TODO ! !  !
        ///saveController.SaveMissions();
        ///

    }

    public void Reject()
    {
        Status = MissionStatusEnum.Rejected;

        ConditionManager.Instance.RemoveCondition(MissionName);

        // 3. Save Mission status in game

        //// TODO ! ! !
    }

    // Assign geting reward as Model End Action
    // Bind by hand to specyfic mission step action
    public void GiveReward()
    {
        // TODO status is overwritten during building
        //if (Status != MissionStatusEnum.Accepted)
        //    return;

        var Player = GameObject.FindGameObjectWithTag("Player");

        if (!Player)
            Debug.LogError("MissionStepModel::GetReward - There is no player on scene!!!");

        Player.GetComponent<PlayerActions>().GetReward(Reward);
    }

    public void FinishMission()
    {
        Debug.Log("FinishMission");

        Status = MissionStatusEnum.Finished;

        // 3. remove quest from player list
        RemoveQuestFromList();
    }

    /// <summary>
    /// czy ta akcja ma by wywolywana w buttonie i ma wywoływac inn eakcje z 'end of step actions lsit'
    /// czy ma byc jedna z nich i byc wywoływana przez 'go to next sentence' ....
    /// </summary>
    public void FinishMissionStep()
    {
        MissionStepsList[CurrentStep].Status = MissionStepStatusEnum.Finished;

        CurrentStep++;

        // build without starting
        BuildMission(MissionStepsList);
    }

    /// <summary>
    /// Alias dla tego co powinna robić logika 'GoToNextStep' w Missjach
    /// </summary>
    public void FinishMissionStepAndGoToNext()
    {
        MissionStepsList[CurrentStep].Status = MissionStepStatusEnum.Finished;

        CurrentStep++;


        // build & start 
        StartDialogue();
    }


    public bool CheckStepFinalCondition()
    {
        if (MissionStepsList[CurrentStep].CheckCondition())
        {
            //MissionStepsList[CurrentStep].GiveReward();

            MissionStepsList[CurrentStep].Status = MissionStepStatusEnum.Finished;
        }
        else
        {
            // Show dialoge with sentence like "you dont compleeted requirements"
            Debug.Log("Soprry you dont meet the criteria yet...");

            return false;
        }

        return true;
    }

    // dialogue components

    public void StartDialogue()
    {
        // 1. Build
        BuildMission(MissionStepsList);

        // 2. Show first step
        ShowStep();
    }

    public void BreakDialogueStep()
    {
        foreach (var MissionStep in MissionStepsList)
        {
            // NIKE TYLKO ACTIVE !!

            if ((MissionStep.Status == MissionStepStatusEnum.Active || MissionStep.Status == MissionStepStatusEnum.AfterCondition) && MissionStep.DialogueStep.GetCurrentStep().DialogueController.CurrentPanel != null)
            {
                MissionStep.DialogueStep.GetCurrentStep().DialogueController.CloseCurrentPanel(); // close panel 

                break;
            }
        }
    }

    public void ShowStep()
    {
        foreach (var MissionStep in MissionStepsList)
        {
            // jesli krok jest aktywny & ma niewypowiedziane zdania
            if ((MissionStep.Status == MissionStepStatusEnum.Active || MissionStep.Status == MissionStepStatusEnum.AfterCondition) && MissionStep.DialogueStep.GetCurrentStep()?.DialogueController.listOfDialogue.Count != 0)
            {
                MissionStep.DialogueStep.StartDialogue();

                break;
            }
            /*
                            // jesli stan jest oczekujacy && dialog nie został w całości przegadany
                            // jesli warnek jest zpeniony - idz dalej - nie, czeksaj
                        if (MissionStep.Status == MissionStepStatusEnum.Pending && MissionStep.DialogueStep.GetCurrentStep().DialogueController.listOfDialogue.Count != 0)
                        {
                            // Check or register condition.....
                            // 1. Register condition
                            //ConditionManager.Instance.RegisterCondition(MissionName, MissionStep.MissionConditions);

                            // 2. register next step action
                            // TODO

                            // 3. Open panel (dialogue) ???
                            MissionStep.DialogueStep.StartDialogue(); // create panel 

                            break;
                        }*/
        }
    }

    public void GoToNextStep()
    {
        foreach (var MissionStep in MissionStepsList)
        {

            // Case I: Do nothing sepciaj just get first Step which wasn't invoked yet
            if (MissionStep.Status == MissionStepStatusEnum.Pending)
            {
                /// var nextSentence = MissionStep.DialogueStep.DialogueController.ShowNextPanel(
                //    MissionStep.DialogueStep.DialogueController
                //);

                //If there is no sentence in Step - go to next one
                /*                if (!nextSentence)
                                {
                                    MissionStep.Status = MissionStepStatusEnum.Finished;

                                    ShowStep();
                                }
                */
                break;
            }

            // Case II: Before go foward we must check final condition
            if (MissionStep.Status == MissionStepStatusEnum.Active)
            {
                // po co to ? ? ? - obecnie warunek misji jest sprawdazany nankoncu podanego stepu dialogu 
                // po spełnieniu step misji oznaczany jest jako ukończony
                var conditionResult = CheckStepFinalCondition();

                if (conditionResult)
                    ShowStep();

                break;
            }
        }
    }

    public void BuildMission()
    {
        BuildMission(MissionStepsList);
    }

    private void BuildMission(List<MissionStepModel> Mission)
    {
        // Obligatory
        if (Status == MissionStatusEnum.None)
            Status = MissionStatusEnum.Available;

        foreach (var missionStep in Mission)
        {
            missionStep.SetSpeakerName(SpeakerName);

            missionStep.Build(this);
        }

        // Additionaly set first step as active
        //Debug.Log("BuildMission - Activate step");
        if (MissionStepsList.Count() > CurrentStep)
            MissionStepsList[CurrentStep].ActivateStep();
        else
            Debug.Log($"Mission [{MissionName}] step {CurrentStep} out of steps list containing {MissionStepsList.Count()}");
    }

    #region Dialogue Status API
    /// <summary>
    /// Function to reset rememebered dialogue status
    /// 
    /// (Scriptable objects clones are overwritten during clone modification)
    /// </summary>
    public void ResetMission()
    {
        Status = MissionStatusEnum.None;

        CurrentStep = 0;

        MissionStepsList.ForEach(step => step.ResetMissionStep());
    }

    public void UpdateMissionState(MissionData missionData)
    {
        // 1 Rule - speaker name shouldnt change !!! its our 'key'

        Status = missionData.Status;

        CurrentStep = missionData.CurrentStep;

        for (int i = 0; i < missionData.MissionStepsDataList.Count; i++)
        {
            MissionStepsList[i].UpdateMissionStepState(missionData.MissionStepsDataList[i]);
        }
    }
    #endregion

    public MissionStepModel GetCurrentStep()
    {
        return MissionStepsList[CurrentStep];
    }

    #region Quest managment

    public void CreateQuestOnList()
    {
        // WHERE IS CONDITION TO CHECK IF MISSION ALREADY EXISTS ??? ??? ???

        // 2. Add mission to Player Panel :D
        TaskUIManager.Instance.Add(PlayerTask);

        // 3. Save Player Quest Panel status & (somehow) mission status in game


        // Don't save quest in this moement on list because mission proggrss isnt saved before using
        // teleport or saving proggress by player - data consistency

/*
        var saveController = GameObject.FindObjectOfType<SaveController>();
        if (saveController == null)
            throw new Exception($"There is no SaveController component on scene!!!");

        saveController.GetComponent<SaveController>().SavePlayerQuests();
*/
    }

    public void RemoveQuestFromList()
    {
        var task = TaskUIManager.Instance.FindTaskByName(PlayerTask.Title);

        if (task.Count == 0)
            Debug.LogError($"Task '{PlayerTask.Title}' not found");
        else
            TaskUIManager.Instance.RemoveByName(PlayerTask.Title);
    }

    /// <summary>
    /// Po co misja idwoluje sie do dziecka zamiast ustawic to samemu?
    /// 
    /// Wprzyszlosci ustawic nowy content w stepei!
    /// 
    /// IMPORANT:
    /// nadpisanie w jednym kroku nadpisuje żródłowy Description w Taku obiektu Mission!!!
    /// </summary>
    /// <param name="newMissionissue"></param>
    public void PlayerQuestContentManage(string newMissionissue)
    {
        var task = TaskUIManager.Instance.FindTaskByName(PlayerTask.Title);

        if (task.Count() == 0)
            CreateQuestOnList();

        // manually setupped new contrent for wqizard first mission script
        ((TaskUIManager)TaskUIManager.Instance).ChangeTaskIssue(PlayerTask.Title, newMissionissue);
    }
    #endregion
}