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

namespace M2DVisualQuestEditor
{
    [Serializable]
    public class MetadataEntry
    {
        public string key;
        public string value;
    }

    [Serializable]
    public class NodeData
    {
        public string nodeId;
        public Vector2 position;
        public string nodeType;
        public string dataReference;
        public string role;
        public List<MetadataEntry> metadata;
    }

    [Serializable]
    public class ConnectionData
    {
        public string fromNodeId;
        public string toNodeId;
        public string fromPortName;
        public string toPortName;
    }

    [Serializable]
    public class StickyNoteData
    {
        public Vector2 position;
        public string contents;
    }

    [CreateAssetMenu(fileName = "QuestGraph", menuName = "M2D Visual Quest Editor/Quest Graph Data")]
    public class QuestGraphData : ScriptableObject
    {
        [Header("Quest Reference")]
        [Tooltip("The Quest asset this graph visualizes")]
        public Gyvr.Mythril2D.Quest questAsset;

        [Header("Graph Layout")]
        public Vector3 viewPosition = Vector3.zero;
        public Vector3 viewScale = Vector3.one;

        [Header("Nodes")]
        public List<NodeData> nodes = new List<NodeData>();

        [Header("Connections")]
        public List<ConnectionData> connections = new List<ConnectionData>();

        [Header("Sticky Notes")]
        public List<StickyNoteData> stickyNotes = new List<StickyNoteData>();

        public NodeData GetNode(string nodeId)
        {
            return nodes.Find(n => n.nodeId == nodeId);
        }

        public void SetNode(NodeData node)
        {
            int index = nodes.FindIndex(n => n.nodeId == node.nodeId);
            if (index >= 0)
            {
                nodes[index] = node;
            }
            else
            {
                nodes.Add(node);
            }
        }

        public void RemoveNode(string nodeId)
        {
            nodes.RemoveAll(n => n.nodeId == nodeId);
            connections.RemoveAll(c => c.fromNodeId == nodeId || c.toNodeId == nodeId);
        }

        public void AddConnection(ConnectionData connection)
        {
            if (!connections.Exists(c => 
                c.fromNodeId == connection.fromNodeId && 
                c.toNodeId == connection.toNodeId &&
                c.fromPortName == connection.fromPortName &&
                c.toPortName == connection.toPortName))
            {
                connections.Add(connection);
            }
        }

        public void RemoveConnection(string fromNodeId, string toNodeId)
        {
            connections.RemoveAll(c => c.fromNodeId == fromNodeId && c.toNodeId == toNodeId);
        }

        public void ApplyDialogueRolesToQuest(Gyvr.Mythril2D.Quest quest)
        {
            if (quest == null) return;

            var offerDialogueField = typeof(Gyvr.Mythril2D.Quest).GetField("m_questOfferDialogue", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
            var hintDialogueField = typeof(Gyvr.Mythril2D.Quest).GetField("m_questHintDialogue", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
            var completedDialogueField = typeof(Gyvr.Mythril2D.Quest).GetField("m_questCompletedDialogue", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
            var overridesField = typeof(Gyvr.Mythril2D.Quest).GetField("m_questHintDialogueOverrides", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);

            if (overridesField != null)
            {
                var overrides = overridesField.GetValue(quest) as azixMcAze.SerializableDictionary.SerializableDictionary<Gyvr.Mythril2D.QuestTask, Gyvr.Mythril2D.DialogueSequence>;
                if (overrides != null)
                {
                    overrides.Clear();
                }
            }

            foreach (var nodeData in nodes)
            {
                if (nodeData.nodeType != "Dialogue" || string.IsNullOrEmpty(nodeData.role))
                    continue;

                if (int.TryParse(nodeData.dataReference, out int instanceId))
                {
#pragma warning disable CS0618
                    var dialogue = UnityEditor.EditorUtility.InstanceIDToObject(instanceId) as Gyvr.Mythril2D.DialogueSequence;
#pragma warning restore CS0618
                    if (dialogue != null)
                    {
                        if (nodeData.role == "QuestOffer" && offerDialogueField != null)
                            offerDialogueField.SetValue(quest, dialogue);
                        else if (nodeData.role == "QuestHint" && hintDialogueField != null)
                            hintDialogueField.SetValue(quest, dialogue);
                        else if (nodeData.role == "QuestCompleted" && completedDialogueField != null)
                            completedDialogueField.SetValue(quest, dialogue);
                    }
                }
            }

            UnityEditor.EditorUtility.SetDirty(quest);
        }

        public void LoadDialogueRolesFromQuest(Gyvr.Mythril2D.Quest quest)
        {
            if (quest == null) return;

            var offerDialogueField = typeof(Gyvr.Mythril2D.Quest).GetField("m_questOfferDialogue", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
            var hintDialogueField = typeof(Gyvr.Mythril2D.Quest).GetField("m_questHintDialogue", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
            var completedDialogueField = typeof(Gyvr.Mythril2D.Quest).GetField("m_questCompletedDialogue", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
            var overridesField = typeof(Gyvr.Mythril2D.Quest).GetField("m_questHintDialogueOverrides", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);

            var offerDialogue = offerDialogueField?.GetValue(quest) as Gyvr.Mythril2D.DialogueSequence;
            var hintDialogue = hintDialogueField?.GetValue(quest) as Gyvr.Mythril2D.DialogueSequence;
            var completedDialogue = completedDialogueField?.GetValue(quest) as Gyvr.Mythril2D.DialogueSequence;
            var overrides = overridesField?.GetValue(quest) as azixMcAze.SerializableDictionary.SerializableDictionary<Gyvr.Mythril2D.QuestTask, Gyvr.Mythril2D.DialogueSequence>;

            foreach (var nodeData in nodes)
            {
                if (nodeData.nodeType != "Dialogue")
                    continue;

                if (int.TryParse(nodeData.dataReference, out int instanceId))
                {
#pragma warning disable CS0618
                    var dialogue = UnityEditor.EditorUtility.InstanceIDToObject(instanceId) as Gyvr.Mythril2D.DialogueSequence;
#pragma warning restore CS0618
                    if (dialogue != null)
                    {
                        if (dialogue == offerDialogue)
                            nodeData.role = "QuestOffer";
                        else if (dialogue == hintDialogue)
                            nodeData.role = "QuestHint";
                        else if (dialogue == completedDialogue)
                            nodeData.role = "QuestCompleted";
                        else
                        {
                            bool isHintOverride = false;
                            if (overrides != null)
                            {
                                for (int i = 0; i < quest.tasks.Length; i++)
                                {
                                    if (overrides.ContainsKey(quest.tasks[i]) && overrides[quest.tasks[i]] == dialogue)
                                    {
                                        nodeData.role = $"HintOverride_{i}";
                                        isHintOverride = true;
                                        break;
                                    }
                                }
                            }
                            
                            if (!isHintOverride)
                                nodeData.role = "";
                        }
                    }
                }
            }
        }
    }
}
