using Robust.Shared.Containers;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;

namespace Content.Shared.Hands.Components;

[NetworkedComponent]
public abstract class SharedHandsComponent : Component
{
    /// <summary>
    ///     The currently active hand.
    /// </summary>
    [ViewVariables]
    public Hand? ActiveHand;

    /// <summary>
    ///     The item currently held in the active hand.
    /// </summary>
    [ViewVariables]
    public EntityUid? ActiveHandEntity => ActiveHand?.HeldEntity;

    [ViewVariables]
    public Dictionary<string, Hand> Hands = new();

    public int Count => Hands.Count;

    /// <summary>
    ///     List of hand-names. These are keys for <see cref="Hands"/>. The order of this list determines the order in which hands are iterated over.
    /// </summary>
    public List<string> SortedHands = new();

    /// <summary>
    ///     The amount of throw impulse per distance the player is from the throw target.
    /// </summary>
    [DataField("throwForceMultiplier")]
    [ViewVariables(VVAccess.ReadWrite)]
    public float ThrowForceMultiplier { get; set; } = 10f; //should be tuned so that a thrown item lands about under the player's cursor

    /// <summary>
    ///     Distance after which longer throw targets stop increasing throw impulse.
    /// </summary>
    [DataField("throwRange")]
    [ViewVariables(VVAccess.ReadWrite)]
    public float ThrowRange { get; set; } = 8f;
}

[Serializable, NetSerializable]
public sealed class Hand
{
    [ViewVariables]
    public string Name { get; }

    [ViewVariables]
    public HandLocation Location { get; }

    /// <summary>
    ///     The container used to hold the contents of this hand. Nullable because the client must get the containers via <see cref="ContainerManagerComponent"/>,
    ///     which may not be synced with the server when the client hands are created.
    /// </summary>
    [ViewVariables, NonSerialized]
    public ContainerSlot? Container;

    [ViewVariables]
    public EntityUid? HeldEntity => Container?.ContainedEntity;

    public bool IsEmpty => HeldEntity == null;

    public Hand(string name, HandLocation location, ContainerSlot? container = null)
    {
        Name = name;
        Location = location;
        Container = container;
    }
}

[Serializable, NetSerializable]
public sealed class HandsComponentState : ComponentState
{
    public readonly List<Hand> Hands;
    public readonly List<string> HandNames;
    public readonly string? ActiveHand;

    public HandsComponentState(SharedHandsComponent handComp)
    {
        Hands = new(handComp.Hands.Values);
        HandNames = handComp.SortedHands;
        ActiveHand = handComp.ActiveHand?.Name;
    }
}

/// <summary>
///     What side of the body this hand is on.
/// </summary>
public enum HandLocation : byte
{
    Left,
    Middle,
    Right
}
