// RadialMenuWidget.h
// Container for the radial menu, now a CommonUI activatable widget. It owns the
// CommonUI input bindings (Confirm / Back) and routes them to the controller,
// which still owns all state (time dilation, hover, Entries). The widget also
// spawns one URadialSliceWidget per entry at runtime (variable slice count).

#pragma once

#include "CoreMinimal.h"
#include "CommonActivatableWidget.h"
#include "Engine/DataTable.h" // FDataTableRowHandle
#include "RadialMenuController.h" // for FRadialMenuEntry
#include "RadialMenuWidget.generated.h"

class UCanvasPanel;
class URadialSliceWidget;
struct FUIActionBindingHandle;

UCLASS(Abstract)
class URadialMenuWidget : public UCommonActivatableWidget
{
    GENERATED_BODY()

public:
    // Called by the controller after CreateWidget, before activation. Stores the
    // owning controller so action handlers can route back to it, then builds the
    // slices.
    void InitializeFromController(URadialMenuController* InController,
        const TArray<FRadialMenuEntry>& InEntries);

    // Called when the hovered slice changes. Stored and applied each tick.
    void SetHoveredSegment(int32 Index);

protected:
    virtual void NativeOnActivated() override;
    virtual void NativeOnDeactivated() override;
    virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;

    // Left-click confirm. Handled directly here rather than as a CommonUI action
    // binding, because CommonUI routes left mouse through its Default Click Action
    // system (separate from RegisterUIActionBinding), so a click-mapped action
    // never reaches a normal binding. Intercepting the pointer event sidesteps that.
    virtual FReply NativeOnMouseButtonDown(const FGeometry& InGeometry,
        const FPointerEvent& InMouseEvent) override;

    // Gamepad slice selection. When this widget is the active CommonUI node, the
    // analog sticks are routed here (NOT to the PlayerController), which is why
    // GetInputAnalogStickState returns 0 from the controller while a menu is up.
    // We read the right stick from the analog event and drive hover directly.
    virtual FReply NativeOnAnalogValueChanged(const FGeometry& InGeometry,
        const FAnalogInputEvent& InAnalogEvent) override;

    // CommonUI focus: returning the root keeps gamepad/keyboard focus on us so
    // the bound actions fire while the wheel is open.
    virtual UWidget* NativeGetDesiredFocusTarget() const override;

    // --- CommonUI input action assets (assign in the widget BP defaults) ------
    // CommonUI input action rows. These are FDataTableRowHandle pointing at your
    // CommonInputActionDataTable rows (the same rows your other screens use for
    // accept/back), so the on-screen action bar and key mapping stay consistent.
    UPROPERTY(EditDefaultsOnly, Category = "Radial Menu|Input",
        meta = (RowType = "/Script/CommonUI.CommonInputActionDataBase"))
    FDataTableRowHandle ConfirmAction;

    // Bound explicitly so our cancel path runs (restore time, broadcast -1)
    // rather than CommonUI just popping the widget on Back.
    UPROPERTY(EditDefaultsOnly, Category = "Radial Menu|Input",
        meta = (RowType = "/Script/CommonUI.CommonInputActionDataBase"))
    FDataTableRowHandle BackAction;

    // Root canvas the slices are spawned into.
    UPROPERTY(meta = (BindWidget))
    TObjectPtr<UCanvasPanel> SliceCanvas = nullptr;

    UPROPERTY(EditDefaultsOnly, Category = "Radial Menu")
    TSubclassOf<URadialSliceWidget> SliceWidgetClass;

    UPROPERTY(EditDefaultsOnly, Category = "Radial Menu")
    TObjectPtr<UMaterialInterface> SliceMaterial = nullptr;

    UPROPERTY(EditDefaultsOnly, Category = "Radial Menu")
    float MenuDiameter = 420.f;

private:
    // Action handlers, bound in NativeOnActivated.
    void HandleConfirm();
    void HandleBack();

    void BuildSlices(const TArray<FRadialMenuEntry>& InEntries);

    UPROPERTY(Transient)
    TWeakObjectPtr<URadialMenuController> OwningController;

    UPROPERTY(Transient)
    TArray<TObjectPtr<URadialSliceWidget>> Slices;

    // Handles kept so we can unregister on deactivation.
    FUIActionBindingHandle ConfirmHandle;
    FUIActionBindingHandle BackHandle;

    int32 HoveredIndex = -1;

    // Latest right-stick axis values, cached across single-axis analog events so
    // we can recompute the full 2D direction whenever either axis updates.
    float RightStickX = 0.f;
    float RightStickY = 0.f;
};