#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Content.Shared.GameObjects.Components.Body.Part;
using Content.Shared.GameObjects.Components.Body.Part.Property;
using Robust.Shared.Interfaces.GameObjects;
namespace Content.Shared.GameObjects.Components.Body
{
///
/// Component representing a collection of s
/// attached to each other.
///
public interface IBody : IComponent, IBodyPartContainer
{
public string? TemplateName { get; }
public string? PresetName { get; }
// TODO BODY tf is this
///
/// Maps all parts on this template to its BodyPartType.
/// For instance, "right arm" is mapped to "BodyPartType.arm" on the humanoid
/// template.
///
public Dictionary Slots { get; }
///
/// Maps slots to the part filling each one.
///
public IReadOnlyDictionary Parts { get; }
// TODO BODY what am i doing
///
/// Maps limb name to the list of their connections to other limbs.
/// For instance, on the humanoid template "torso" is mapped to a list
/// containing "right arm", "left arm", "left leg", and "right leg".
/// This is mapped both ways during runtime, but in the prototype only one
/// way has to be defined, i.e., "torso" to "left arm" will automatically
/// map "left arm" to "torso".
///
public Dictionary> Connections { get; }
///
/// Maps a template slot to the ID of the
/// that should fill it. E.g. "right arm" : "BodyPart.arm.basic_human".
///
public IReadOnlyDictionary PartIds { get; }
///
/// Adds the given into the given slot.
///
/// True if successful, false otherwise.
bool TryAddPart(string slot, IBodyPart part, bool force = false);
bool HasPart(string slot);
bool HasPart(IBodyPart part);
///
/// Removes the given reference, potentially
/// dropping other BodyParts if they
/// were hanging off of it.
///
void RemovePart(IBodyPart part);
///
/// Removes the body part in slot from this body,
/// if one exists.
///
/// The slot to remove it from.
/// True if the part was removed, false otherwise.
bool RemovePart(string slot);
///
/// Removes the body part from this body, if one exists.
///
/// The part to remove from this body.
/// The slot that the part was in, if any.
/// True if was removed, false otherwise.
bool RemovePart(IBodyPart part, [NotNullWhen(true)] out string? slotName);
///
/// Disconnects the given reference, potentially
/// dropping other BodyParts if they
/// were hanging off of it.
///
/// The part to drop.
///
/// All of the parts that were dropped, including .
///
///
/// True if the part was dropped, false otherwise.
///
bool TryDropPart(IBodyPart part, [NotNullWhen(true)] out List? dropped);
///
/// Recursively searches for if is connected to
/// the center.
///
/// The body part to find the center for.
/// True if it is connected to the center, false otherwise.
bool ConnectedToCenter(IBodyPart part);
///
/// Finds the central , if any, of this body based on
/// the . For humans, this is the torso.
///
/// The if one exists, null otherwise.
IBodyPart? CenterPart();
///
/// Returns whether the given part slot name exists within the current
/// .
///
/// The slot to check for.
/// True if the slot exists in this body, false otherwise.
bool HasSlot(string slot);
///
/// Finds the in the given if
/// one exists.
///
/// The part slot to search in.
/// The body part in that slot, if any.
/// True if found, false otherwise.
bool TryGetPart(string slot, [NotNullWhen(true)] out IBodyPart? result);
///
/// Finds the slotName that the given resides in.
///
///
/// The to find the slot for.
///
/// The slot found, if any.
/// True if a slot was found, false otherwise
bool TryGetSlot(IBodyPart part, [NotNullWhen(true)] out string? slot);
///
/// Finds the in the given
/// if one exists.
///
/// The slot to search in.
///
/// The of that slot, if any.
///
/// True if found, false otherwise.
bool TryGetSlotType(string slot, out BodyPartType result);
///
/// Finds the names of all slots connected to the given
/// for the template.
///
/// The slot to search in.
/// The connections found, if any.
/// True if the connections are found, false otherwise.
bool TryGetSlotConnections(string slot, [NotNullWhen(true)] out List? connections);
///
/// Grabs all occupied slots connected to the given slot,
/// regardless of whether the given is occupied.
///
/// The slot name to find connections from.
/// The connected body parts, if any.
///
/// True if successful, false if the slot couldn't be found on this body.
///
bool TryGetPartConnections(string slot, [NotNullWhen(true)] out List? connections);
///
/// Grabs all parts connected to the given , regardless
/// of whether the given is occupied.
///
/// The part to find connections from.
/// The connected body parts, if any.
///
/// True if successful, false if the part couldn't be found on this body.
///
bool TryGetPartConnections(IBodyPart part, [NotNullWhen(true)] out List? connections);
///
/// Finds all s of the given type in this body.
///
/// A list of parts of that type.
List GetPartsOfType(BodyPartType type);
///
/// Finds all s with the given property in this body.
///
/// The property type to look for.
/// A list of parts with that property.
List<(IBodyPart part, IBodyPartProperty property)> GetPartsWithProperty(Type type);
///
/// Finds all s with the given property in this body.
///
/// The property type to look for.
/// A list of parts with that property.
List<(IBodyPart part, T property)> GetPartsWithProperty() where T : class, IBodyPartProperty;
// TODO BODY Make a slot object that makes sense to the human mind, and make it serializable. Imagine the possibilities!
KeyValuePair SlotAt(int index);
KeyValuePair PartAt(int index);
}
}