using System;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;

namespace Robust.Shared.Analyzers;

/// <summary>
///     When a component is marked with this attribute, any members it has marked with <see cref="AutoNetworkedFieldAttribute"/>
///     will automatically be replicated using component states to clients. Systems which need to have more intelligent
///     component state replication beyond just directly setting variables should not use this attribute.
/// </summary>
/// <example>
/// <code>
///     // In shared code...
///     [RegisterComponent, AutoGenerateComponentState]
///     public sealed class MyComponent : Component
///     {
///         // Indicate to the generator we want to network this field.
///         // Doesn't need to be a DataField for this to work!
///         [AutoNetworkedField]
///         public int Counter;
///     }
///     <br/>
///     public sealed class MySystem : EntitySystem
///     {
///         public void AddToCounter(Entity&lt;MyComponent&gt; entity)
///         {
///             entity.Comp.Counter += 1;
///             <br/>
///             // Dirty the entity, and the auto-generated state handling will do the rest to ensure
///             // all our AutoNetworkedFields are sent to the client.
///             Dirty(entity);
///         }
///     }
/// </code>
/// </example>
/// <seealso cref="AutoNetworkedFieldAttribute"/>
/// <seealso cref="AfterAutoHandleStateEvent"/>
/// <seealso cref="ComponentState"/>
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
[BaseTypeRequired(typeof(IComponent))]
public sealed class AutoGenerateComponentStateAttribute : Attribute
{
    /// <summary>
    ///     If this is true, the autogenerated code will raise a <see cref="AfterAutoHandleStateEvent"/> component event
    ///     so that user-defined systems can have effects after handling state without redefining all replication.
    /// </summary>
    public readonly bool RaiseAfterAutoHandleState;

    /// <summary>
    ///     Should delta states be generated for every field.
    /// </summary>
    public readonly bool FieldDeltas;

    public AutoGenerateComponentStateAttribute(bool raiseAfterAutoHandleState = false, bool fieldDeltas = false)
    {
        RaiseAfterAutoHandleState = raiseAfterAutoHandleState;
        FieldDeltas = fieldDeltas;
    }
}

/// <summary>
///     Used to mark component members which should be automatically replicated, assuming the component is marked with
///     <see cref="AutoGenerateComponentStateAttribute"/>.
/// </summary>
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class AutoNetworkedFieldAttribute : Attribute
{
}

/// <summary>
///     Raised as a component event after auto handling state is done, if
///     <see cref="AutoGenerateComponentStateAttribute.RaiseAfterAutoHandleState"/> is true, so that other systems
///     can have effects after handling state without having to redefine all replication.
/// </summary>
[ByRefEvent, ComponentEvent]
public record struct AfterAutoHandleStateEvent(IComponentState State);
