﻿using System;
using System.Collections.Generic;
using UnityEditor.Experimental.GraphView;
using UnityEngine;

namespace E.Story
{
    /// <summary>
    /// 故事运行器（可根据实际项目需求修改此脚本）
    /// </summary>
    public class StoryRunner : MonoBehaviour
    {
        [Header("主要组件")]
        [SerializeField] private StoryUI storyUI;

        [Header("当前故事")]
        [SerializeField] private StoryDataSO currentStory;

        [Header("运行时变量")]
        [SerializeField] [ReadOnly] private bool isStoryPlaying;
        [SerializeField] [ReadOnly] private NodeData currentNodeData;
        [SerializeField] [ReadOnly] private NodeData nextNodeData;
        [SerializeField] [ReadOnly] private int currentSentenceIndex;
        [SerializeField] [ReadOnly] private List<VarData> varDatas;


        private void Start()
        {
            storyUI.ShowMenu();
            storyUI.HideBGI();
            storyUI.HidePortrait();
            storyUI.HideDialogue();
            storyUI.HideBranchs();
            storyUI.HideVars();
        }

        private void Update()
        {
            if (Input.GetKeyDown(KeyCode.S))
            {
                StartStory();
            }

            if (Input.GetKeyDown(KeyCode.Space))
            {
                NextStep();
            }
        }

        /// <summary>
        /// 开始故事
        /// </summary>
        public void StartStory()
        {
            if (currentStory == null)
            {
                Debug.LogError("未指定故事");
                return;
            }

            NodeData nodeData = currentStory.GetStartNode();
            if (nodeData == null)
            {
                Debug.LogError("开始节点不存在");
                return;
            }

            isStoryPlaying = true;
            varDatas = DataUtility.CloneVarDatas(currentStory.VarDatas);

            storyUI.HideMenu();
            storyUI.HideBGI();
            storyUI.HidePortrait();
            storyUI.HideDialogue();
            storyUI.HideBranchs();
            storyUI.ShowVars(varDatas);

            DoNode(nodeData);
        }

        /// <summary>
        /// 结束故事
        /// </summary>
        public void EndStory()
        {
            //重置数据
            isStoryPlaying = false;
            currentNodeData = null;
            nextNodeData = null;
            currentSentenceIndex = 0;
            varDatas = null;

            // 重置UI
            storyUI.ShowMenu();
            storyUI.HideBGI();
            storyUI.HidePortrait();
            storyUI.HideDialogue();
            storyUI.HideBranchs();
            storyUI.HideVars();
        }

        /// <summary>
        /// 执行节点
        /// </summary>
        /// <param name="nodeID">节点GUID</param>
        public void DoNode(string nodeID)
        {
            NodeData nodeData = currentStory.GetNode(nodeID);
            DoNode(nodeData);
        }

        /// <summary>
        /// 执行节点
        /// </summary>
        /// <param name="nodeData">节点数据</param>
        public void DoNode(NodeData nodeData)
        {
            if (!isStoryPlaying)
            {
                Debug.LogError("故事未开始");
                return;
            }

            currentNodeData = nodeData;

            if (nodeData == null)
            {
                Debug.LogError("节点不存在");
                return;
            }

            // 根据当前节点类型执行对应的操作
            switch (nodeData.Type)
            {
                case NodeType.Start:
                    Debug.Log($"执行开始节点：{nodeData.Title}\n故事开始");
                    NextStep();
                    break;

                case NodeType.End:
                    Debug.Log($"执行结束节点：{nodeData.Title}\n故事结束");
                    EndStory();
                    break;

                case NodeType.Dialogue:
                    Debug.Log($"执行对话节点：{nodeData.Title}");
                    ShowPortrait(nodeData.Portrait);
                    ShowSentence(0);
                    break;

                case NodeType.BGI:
                    Debug.Log($"执行背景图片节点：{nodeData.Title}");
                    ShowBGI(nodeData.BGI);
                    NextStep();
                    break;

                case NodeType.Branch:
                    List<ChoiceData> availableChoices =  GetAvailableChoices(nodeData.ChoiceDatas);
                    Debug.Log($"执行分支节点：{nodeData.Title}\n包含有效选项{availableChoices.Count}个");
                    storyUI.ShowBranchs(availableChoices);
                    break;

                case NodeType.Layout:
                    Debug.Log($"执行布局节点：{nodeData.Title}");
                    NextStep();
                    break;

                case NodeType.EditVar:
                    Debug.Log($"执行编辑变量节点：{nodeData.Title}");
                    EditVars();
                    NextStep();
                    break;

                default:
                    break;
            }
        }

        /// <summary>
        /// 执行下个步骤
        /// </summary>
        public void NextStep()
        {
            if (!isStoryPlaying)
            {
                Debug.LogError("故事未开始");
                return;
            }

            if (currentStory == null)
            {
                Debug.LogError("未指定故事");
                return;
            }

            if (currentNodeData == null)
            {
                Debug.LogError("未指定当前节点");
                return;
            }

            nextNodeData = null;
            string nodeID;

            // 根据当前节点类型执行下一步操作
            switch (currentNodeData.Type)
            {
                // 自动执行
                case NodeType.Start:
                case NodeType.BGI:
                case NodeType.Layout:
                case NodeType.EditVar:
                    nodeID = currentNodeData.ChoiceDatas[0].NextNodeID;
                    nextNodeData = currentStory.GetNode(nodeID);
                    break;

                // 停止执行
                case NodeType.End:
                    Debug.LogWarning("故事已结束，没有后续节点。");
                    return;

                // 等待执行
                case NodeType.Dialogue:
                    // 检测下个句子索引是否越界
                    int nextSentenceIndex = currentSentenceIndex + 1;
                    if (nextSentenceIndex >= currentNodeData.SentenceDatas.Count)
                    {
                        // 句子展示完毕，执行下个节点
                        nodeID = currentNodeData.ChoiceDatas[0].NextNodeID;
                        nextNodeData = currentStory.GetNode(nodeID);
                        break;
                    }
                    else
                    {
                        // 句子未展示完毕，展示下个句子
                        ShowSentence(nextSentenceIndex);
                        return;
                    }
                case NodeType.Branch:
                    Debug.LogWarning("请选择一个分支选项");
                    return;

                default:
                    break;
            }

            if (nextNodeData == null)
            {
                Debug.LogError("未连接下个节点。如果故事剧情在此结束，请连接至结束节点。");
                return;
            }

            DoNode(nextNodeData);
        }

        /// <summary>
        /// 显示背景
        /// </summary>
        /// <param name="sprite">背景</param>
        public void ShowBGI(Sprite sprite)
        {
            if (sprite != null)
            {
                storyUI.ShowBGI(sprite);
                Debug.Log($"显示背景：{sprite.name}");
            }
            else
            {
                storyUI.HideBGI();
                Debug.Log($"隐藏背景");
            }
        }

        /// <summary>
        /// 显示立绘
        /// </summary>
        /// <param name="sprite">立绘</param>
        public void ShowPortrait(Sprite sprite)
        {
            if (sprite != null)
            {
                storyUI.ShowPortrait(sprite);
                Debug.Log($"显示立绘：{sprite.name}");
            }
            else
            {
                storyUI.HidePortrait();
                Debug.Log($"隐藏立绘/立绘未指定");
            }
        }

        /// <summary>
        /// 显示句子
        /// </summary>
        public void ShowSentence(int index)
        {
            NodeData node = currentNodeData;
            currentSentenceIndex = index;

            storyUI.ShowDialogue(node.RoleName, node.SentenceDatas[index]);
            Debug.Log($"显示对话：{node.RoleName}（第{index + 1}句）\n{node.SentenceDatas[index].Text}");
        }

        /// <summary>
        /// 获取有效选项数据列表
        /// </summary>
        /// <param name="choiceDatas">选项数据列表</param>
        /// <returns>有效选项数据列表</returns>
        private List<ChoiceData> GetAvailableChoices(List<ChoiceData> choiceDatas)
        {
            List<ChoiceData> datas = new();
            foreach (ChoiceData choiceData in choiceDatas)
            {
                if (IsChoiceAvailable(choiceData))
                {
                    datas.Add(choiceData);
                }
            }

            return datas;
        }

        /// <summary>
        /// 检测选项是否有效
        /// </summary>
        /// <param name="choiceData">选项数据</param>
        /// <returns>是否有效</returns>
        private bool IsChoiceAvailable(ChoiceData choiceData)
        {
            // 如果没设置下个节点，跳过此选项
            if (string.IsNullOrEmpty(choiceData.NextNodeID))
                return false;

            // 遍历所有条件
            List<bool> passes = new();
            foreach (ConditionData conditionData in choiceData.Conditions)
            {
                // 检测索引是否越界
                if (conditionData.VarIndex >= varDatas.Count)
                {
                    Debug.LogError($"目标变量索引越界");
                    // 跳过该条件
                    continue;
                }

                // 获取待对比的变量数据
                VarData varData = varDatas[conditionData.VarIndex];
                // 记录节点是否通过
                bool temp = IsConditionPass(conditionData, varData);
                // 记加入列表
                passes.Add(temp);
            }

            switch (choiceData.DetectMode)
            {
                case ConditionDetectMode.满足全部:
                    foreach (bool pass in passes)
                    {
                        // 如果有任意条件不满足
                        if (!pass)
                        {
                            // 将当前选项标记为不可用
                            return false;
                        }
                    }
                    // 将当前选项标记为可用
                    return true;
                case ConditionDetectMode.满足任意:
                    foreach (bool pass in passes)
                    {
                        // 如果有任意条件满足
                        if (pass)
                        {
                            // 将当前选项标记为可用
                            return true;
                        }
                    }
                    // 将当前选项标记为不可用
                    return false;
            }

            // 默认将当前选项标记为可用
            return true;
        }

        /// <summary>
        /// 检测条件是否通过
        /// </summary>
        /// <param name="conditionData">条件数据</param>
        /// <param name="varData">变量数据</param>
        /// <returns>是否通过</returns>
        private bool IsConditionPass(ConditionData conditionData, VarData varData)
        {
            int value = varData.Value;
            int conditionValue = conditionData.Value;

            // 记录对比结果
            bool temp = false;

            // 执行对应操作
            switch (conditionData.Compare)
            {
                case CompareType.大于:
                    temp = value > conditionValue;
                    break;
                case CompareType.大于等于:
                    temp = value >= conditionValue;
                    break;
                case CompareType.小于:
                    temp = value < conditionValue;
                    break;
                case CompareType.小于等于:
                    temp = value <= conditionValue;
                    break;
                case CompareType.等于:
                    temp = value == conditionValue;
                    break;
                case CompareType.不等于:
                    temp = value != conditionValue;
                    break;
                default:
                    break;
            }

            return temp;
        }

        /// <summary>
        /// 编辑变量
        /// </summary>
        private void EditVars()
        {
            if (varDatas.Count == 0)
            {
                Debug.LogError($"未设置变量");
                return;
            }

            // 获取编辑操作列表
            List<EditVarData> editVarDatas = currentNodeData.EditVarDatas;

            // 遍历列表依次执行
            foreach (EditVarData editVarData in editVarDatas)
            {
                int varIndex = editVarData.VarIndex;
                int editValue = editVarData.Value;

                // 检测索引是否越界
                if (varIndex >= varDatas.Count)
                {
                    Debug.LogError($"目标变量索引越界");
                    break;
                }

                // 获取待编辑的变量
                VarData varData = varDatas[varIndex];

                // 执行对应操作
                switch (editVarData.Operation)
                {
                    case OperationType.加法:
                        varData.Value += editValue;
                        break;
                    case OperationType.乘法:
                        varData.Value *= editValue;
                        break;
                    case OperationType.指定:
                        varData.Value = editValue;
                        break;
                    default:
                        break;
                }
                Debug.Log($"{varData.Key}：{varData.Value}");
            }

            storyUI.UpdateVars();
        }
    }
}