using System;
using KitsuneCafe.ItemSystem;
using KitsuneCafe.System;
using KitsuneCafe.System.Attributes;
using UnityEngine;
using UnityEngine.Events;

namespace KitsuneCafe.Interaction
{
    using Result = IInteractable.Result;

    public class Gate : MonoBehaviour, IInteractable
    {
        public enum Requirement
        {
            None,
            Key,
            Switch
        }

        [SerializeField]
        private bool isOpen;

        [SerializeField]
        private bool isLocked;

        [SerializeField, ShowIf("isLocked")]
        private Requirement requirement;

        [SerializeField, ShowIf("requirement", Requirement.Key)]
        private Item key;

        [SerializeField, ShowIf("requirement", Requirement.Key)]
        private bool consumeKey;

        [SerializeField]
        private UnityEvent opened = default;

        [SerializeField]
        private UnityEvent closed = default;

        public bool IsInteractable => true;
        public bool IsOpen => isOpen;
        public bool IsLocked => isLocked;

        public IResult<Unit, InteractionError> Interact(IInteractor interactor)
        {
            return isOpen switch
            {
                true => TryClose(interactor),
                false => TryOpen(interactor),
            };
        }

        private IResult<Unit, InteractionError> TryClose(IInteractor interactor)
        {
            if (!isOpen)
            {
                return Result.Ok();
            }

            return ForceClosed();
        }

        private IResult<Unit, InteractionError> TryOpen(IInteractor interactor)
        {
            return requirement switch
            {
                _ when isOpen => Result.Ok(),
                _ when !isLocked => ForceOpen(),
                Requirement.None => Result.Err(InteractionErrorCode.Locked),
                Requirement.Key => TryOpenWithKey(interactor),
                Requirement.Switch => Result.Err(InteractionErrorCode.RequiresSwitch),
                var x => throw new ArgumentException($"{gameObject.name} requested invalid requirement type {x}")
            };
        }

        private IResult<Unit, InteractionError> TryOpenWithKey(IInteractor interactor)
        {
            if (interactor.TryGetComponent<IInventory<InventoryItem>>(out var inventory) && inventory.Has(key))
            {
                if (consumeKey)
                {
                    inventory.Remove(key);
                }

                isLocked = false;
                ForceOpen();
                return Result.Ok();
            }
            else
            {
                return Result.Err(InteractionErrorCode.MissingItem);
            }
        }

        public void ForceClosedAndForget()
        {
            isOpen = false;
            closed.Invoke();
        }

        public IResult<Unit, InteractionError> ForceClosed()
        {
            ForceClosedAndForget();
            return Result.Ok();
        }

        public void ForceOpenAndForget()
        {
            isOpen = true;
            opened.Invoke();
        }

        public IResult<Unit, InteractionError> ForceOpen()
        {
            ForceOpenAndForget();
            return Result.Ok();
        }
    }
}
