using Game.Extensions;
using Godot;

namespace Game;

public sealed partial class MeetingControlDragData(MeetingControl meetingControl) : GodotObject
{
    public MeetingControl MeetingControl { get; set; } = meetingControl;
}

[SceneTree]
public partial class MeetingControl : Control
{
    [Export]
    public MeetingPhysicsBox MeetingPhysicsBox;

    private MeetingControl otherMeetingControl;

    public bool DragIsHandled { get; set; }

    public bool ForceDragged { get; set; }

    public override void _Ready()
    {
        // TODO: make this more pretty
        MeetingControlGfx.MeetingResource = MeetingPhysicsBox.MeetingResource;
    }

    public override Variant _GetDragData(Vector2 atPosition)
    {
        var preview = CreatePreview();
        SetDragPreview(preview);
        Visible = false;

        DragIsHandled = false;
        ForceDragged = false;

        return Variant.From(new MeetingControlDragData(this));
    }

    public override bool _CanDropData(Vector2 atPosition, Variant data)
    {
        return data.VariantType == Variant.Type.Object
            && data.AsGodotObject() is MeetingControlDragData;
    }

    public override void _DropData(Vector2 atPosition, Variant data)
    {
        var meetingData = (MeetingControlDragData)data;

        otherMeetingControl = meetingData.MeetingControl;
        var otherParent = otherMeetingControl.GetParent();

        // TODO: refactor mit Signal
        var timeSlot = GetParent<TimeSlot>();
        timeSlot.MeetingControl = otherMeetingControl;

        otherMeetingControl.Reparent(GetParent(), false);
        Reparent(otherParent, false);

        otherMeetingControl.Visible = true;
        otherMeetingControl.DragIsHandled = true;

        if (otherMeetingControl.ForceDragged)
        {
            RespawnPhysicsBoxFromSpawn();
            otherMeetingControl.ForceDragged = false;
        }
    }

    public void StartDrag()
    {
        var preview = CreatePreview();
        var data = Variant.From(new MeetingControlDragData(this));

        ForceDrag(data, preview);

        DragIsHandled = false;
        ForceDragged = true;
    }

    public override void _Notification(int what)
    {
        // Notfall respawn
        if (what == NotificationDragEnd)
        {
            if (DragIsHandled)
                return;

            RespawnPhysicsBoxFromSpawn();
        }
    }

    private void RespawnPhysicsBoxFromSpawn()
    {
        var game = NodeExtensions.GetMain(this);
        game.AddChild(MeetingPhysicsBox);
        MeetingPhysicsBox.Position = game.MeetingSpawn.GlobalPosition;
        QueueFree();
    }

    private Control CreatePreview()
    {
        var copy = Duplicate() as MeetingControl;
        var preview = new Control();
        preview.AddChild(copy);
        copy.Position = new Vector2(-Size.X / 2, -Size.Y / 2);

        return preview;
    }

    public void Animate()
    {
        var tween = CreateTween();

        tween
            .TweenProperty(
                this,
                new NodePath(Control.PropertyName.OffsetTransformScale),
                new Vector2(1.2f, 1.2f),
                0.2f
            )
            .SetTrans(Tween.TransitionType.Back)
            .SetEase(Tween.EaseType.Out);

        tween
            .TweenProperty(
                this,
                new NodePath(Control.PropertyName.OffsetTransformScale),
                Vector2.One,
                0.2f
            )
            .SetTrans(Tween.TransitionType.Quad)
            .SetEase(Tween.EaseType.Out);
    }
}
