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

namespace ScrambleKit.Move
{
    [Serializable]
    public struct InputBinding
    {
        public string inputName;
        public KeyCode key;
        public MouseButton mouseButton;
    }

    public enum MouseButton
    {
        None,
        Left,
        Right
    }

    public class MoveInputSource : MonoBehaviour
    {
        public List<InputBinding> Bindings;
        public bool AIControlled = false;
        public string DebugWatch;

        public Vector2 AimingAt { get; private set; }

        private Dictionary<string, float> triggerTimes = new Dictionary<string, float>();
        private Dictionary<string, bool> helds = new Dictionary<string, bool>();
        private float stunnedUntil;

        public bool ConsumeTrigger(string inputName, float withinTime = 0.2f)
        {
            if(!triggerTimes.ContainsKey(inputName))
                return false;

            if (triggerTimes[inputName] >= Time.time - withinTime)
            {
                triggerTimes[inputName] = -999;
                return true;
            }

            return false;
        }

        public bool CheckHeld(string inputName)
        {
            if (helds.ContainsKey(inputName))
            {
                return helds[inputName];
            }

            return false;
        }

        public void Stun(float time)
        {
            ClearInputs();
            stunnedUntil = Time.fixedTime + time;
        }

        void Update()
        {
            if (IsStunned())
                return;

            if(!AIControlled)
                CheckInputs();
            BuildDebugString();        
        }

        private void BuildDebugString()
        {
            DebugWatch = "";
            foreach (string inputName in triggerTimes.Keys)
                DebugWatch += inputName + " " + (Time.time - triggerTimes[inputName]) + ", ";
        }

        void Start()
        {
            ClearInputs();
        }

        private void ClearInputs()
        {
            foreach (InputBinding b in Bindings)
            {
                helds[b.inputName] = false;
                triggerTimes[b.inputName] = -999;
            }
        }

        private void CheckInputs()
        {
            AimingAt = Camera.main.ScreenToWorldPoint(Input.mousePosition);

            foreach (InputBinding b in Bindings)
            {
                if (Input.GetKeyDown(b.key) || MouseTriggered(b))
                    triggerTimes[b.inputName] = Time.time;

                helds[b.inputName] = (Input.GetKey(b.key) || MouseHeld(b));
            }
        }

        private bool MouseTriggered(InputBinding b)
        {
            if (b.mouseButton == MouseButton.Left)
                return Input.GetMouseButtonDown(0);
            else if (b.mouseButton == MouseButton.Right)
                return Input.GetMouseButtonDown(1);
            else
                return false;
        }

        private bool MouseHeld(InputBinding b)
        {
            if (b.mouseButton == MouseButton.Left)
                return Input.GetMouseButton(0);
            else if (b.mouseButton == MouseButton.Right)
                return Input.GetMouseButton(1);
            else
                return false;
        }

        public void AITrigger(string inputName)
        {
            if (!IsStunned())
                triggerTimes[inputName] = Time.time;
        }

        public void AIHold(string inputName)
        {
            if (!IsStunned())
                helds[inputName] = true;
        }

        public void AIRelease(string inputName)
        {
            if (!IsStunned())
                helds[inputName] = false;
        }

        public void AIAimAt(Vector2 point)
        {
            if (!IsStunned())
                AimingAt = point;
        }

        private bool IsStunned()
        {
            return stunnedUntil > Time.fixedTime;
        }
    }
}