using Godot;
using static ld48.Extensions;

public class Hook : KinematicBody2D {
    private static readonly Vector2 gravity = new Vector2(0f, 0.2f);
    public Vector2 velocity;
    public RopeController rope;
    public bool affixed;

    public bool retracting;
    private float retractSpeed;

    private RayCast2D ropeRay;

    private Sprite sprite;

    public override void _Ready() {
        base._Ready();
        
        ropeRay = GetNode<RayCast2D>("RopeRay");
        sprite = GetNode<Sprite>("Sprite");
    }

    public override void _Process(float delta) {
        base._Process(delta);
        
        Update();
    }

    public override void _PhysicsProcess(float delta) {
        base._PhysicsProcess(delta);
        
        if (retracting) {
            retractSpeed += (50f - retractSpeed) / 30f;
        }
        if (retractSpeed > 0.1f) {
            rope.RetractStart(retractSpeed);
            if (rope.RopeExists()) {
                Position = rope.StartSegment().a;
            }
        }

        if (affixed) return;

        velocity += gravity;
        
        var tV = velocity / 60f;

        for (int d = 0; d < 60; d++) {
            var collision = MoveAndCollide(tV);
            
            if (collision != null) {
                rope.HookHit(this, collision.Position, collision.Normal);
                rope.StartSegment().freeze = true;
                rope.StartSegment().slippable = true;
            }

            if (!rope.RopeExists()) return;
            rope.StartSegment().a = Position;
            
            ropeRay.CastTo = rope.StartSegment().b - Position;
            ropeRay.ForceRaycastUpdate();

            if (ropeRay.IsColliding()) {
                rope.BackAffixRope(ropeRay.GetCollisionPoint(), ropeRay.GetCollisionNormal());
            }
        }
        
        var totalRope = rope.RopeLength();
        var ropeFriction = 1f;
        
        if (Hero.maxRopeLength < totalRope) {
            var ropeNormal = rope.StartSegment().Direction();
            var offset = totalRope - Hero.maxRopeLength;
            velocity -= velocity.Project(ropeNormal) * ropeFriction;
            MoveAndSlide(ropeNormal * offset * ropeFriction, Vector2.Up);
        }

        sprite.Rotation = velocity.Angle() + Mathf.Pi/2f;
        sprite.Position = velocity.Normalized() * 3f;

    }
}

