using System;
using KitsuneCafe.System;
using UnityEngine;

namespace KitsuneCafe.Interaction
{
    public enum InteractionErrorCode
    {
        None,
        Locked,
        MissingItem,
        RequiresSwitch,
        Generic
    }

    [Serializable]
    public readonly struct InteractionError : IEquatable<InteractionError>
    {
        public readonly InteractionErrorCode Code;
        public readonly string Message;

        private InteractionError(InteractionErrorCode code, string message)
        {
            Code = code;
            Message = message;
        }

        public static InteractionError None => new(InteractionErrorCode.None, string.Empty);
        public static InteractionError Locked(string message = "The door is locked.") => new(InteractionErrorCode.Locked, message);
        public static InteractionError MissingItem(string message = "This requires a key.") => new(InteractionErrorCode.MissingItem, message);
        public static InteractionError RequiresSwitch(string message = "This is unlocked from somewhere else.") => new(InteractionErrorCode.RequiresSwitch, message);
        public static InteractionError Generic(string message = "An unknown interaction error occurred.") => new(InteractionErrorCode.Generic, message);

        public static implicit operator InteractionError(InteractionErrorCode code)
        {
            return code switch
            {
                InteractionErrorCode.None => None,
                InteractionErrorCode.Locked => Locked(),
                InteractionErrorCode.MissingItem => MissingItem(),
                InteractionErrorCode.RequiresSwitch => RequiresSwitch(),
                InteractionErrorCode.Generic => Generic(),
                _ => throw new ArgumentOutOfRangeException()
            };
        }

        public bool Equals(InteractionError other)
        {
            return Code == other.Code;
        }

        public override bool Equals(object obj)
        {
            return obj is InteractionError other && Equals(other);
        }

        public override int GetHashCode()
        {
            return HashCode.Combine(Code);
        }

        public override string ToString()
        {
            return $"[{Code}] {Message}";
        }
    }

    public interface IInteractor : IGameObject
    {
        GameObject Root { get; }
    }

    public interface IInteractable : IGameObject
    {
        public static class Result
        {
            public static IResult<Unit, InteractionError> Ok() => System.Result.Ok<Unit, InteractionError>(default);
            public static IResult<Unit, InteractionError> Err(InteractionError error) => System.Result.Err<Unit, InteractionError>(error);
            public static IResult<Unit, InteractionError> Err(InteractionErrorCode error) => System.Result.Err<Unit, InteractionError>(error);
        }

        bool IsInteractable { get; }
        IResult<Unit, InteractionError> Interact(IInteractor interactor);
    }
}