using System;
using EscapeRoomEngine.Engine.Runtime.Utilities;
using UnityEngine;

namespace EscapeRoomEngine.Engine.Runtime.Modules
{
    public enum DoorType
    {
        Entrance = ModuleType.DoorEntrance, Exit = ModuleType.DoorExit
    }
    
    /// <summary>
    /// The main component of any door module.
    /// </summary>
    [Serializable]
    public class DoorModule : Module
    {
        public bool IsEntrance => IsType((ModuleType)DoorType.Entrance);
        public bool IsExit => IsType((ModuleType)DoorType.Exit);

        /// <summary>
        /// The module state of this door as a <see cref="DoorState"/>.
        /// </summary>
        public DoorState DoorState => DoorState.FromState(State);
        /// <summary>
        /// The module state of the connected door as a <see cref="DoorState"/>.
        /// </summary>
        public DoorState ConnectedDoorState => Passage.Other(this).DoorState;

        /// <summary>
        /// Once this property is set, the door is considered to be connected. This property must only be set once.
        /// </summary>
        internal Passage Passage
        {
            get => _passage;
            set
            {
                if (_passage != null)
                {
                    throw new EngineException($"{this} is already connected");
                }
                
                _passage = value;
                if (State != null)
                {
                    DoorState.Connect();
                }
            }
        }

        private Passage _passage;

        internal DoorModule(Space space, DoorModuleDescription description) : base(space, description) {}

        internal override void InstantiateModule(Transform parent)
        {
            base.InstantiateModule(parent);
            
            // the room needs to know about this door
            space.room.AddDoor(this);
        }

        public override string ToString()
        {
            return $"{(IsEntrance ? "Entrance" : IsExit ? "Exit" : "Unknown")} door";
        }

        public static DoorModule FromModule(Module module)
        {
            if (module is DoorModule doorModule)
            {
                return doorModule;
            }
            
            throw new WrongTypeException(typeof(DoorModule), module.GetType(), typeof(Module));
        }
    }
}