
const thing = document.getElementById('cursor-thing');
let updateTimerId;

let lastUpdate = 0;

// targeting
let mouseX = 0;
let mouseY = 0;
let scrollX = document.scrollingElement.scrollLeft;
let scrollY = document.scrollingElement.scrollTop;
const getTargetX = () => mouseX + scrollX;
const getTargetY = () => mouseY + scrollY;

// physics
let xPos = 0;
let yPos = 0;
let angle = 0;
let velocity = 0;
const maxVel = 600;
let accel = 0;
const maxAccel = 1500;
const accelCurve = (x) => maxAccel*(x/200)**3; // maxAccel when >150px distance

// more physics
const slideFric = .9; // coefficient of friction
const turnSpeedCoeff = .08; // coefficient of turning

// other stuff
let brake = false;
const brakeDist = 70;
const duckSize = 50;

// animation
let alt = false;
let lastAlt = 0;


function update() {
    // timing
    thisUpdate = Date.now();
    deltaT = (thisUpdate - lastUpdate)/1000.0;
    lastUpdate = thisUpdate;

    // update trajectory
    targetX = getTargetX();
    targetY = getTargetY();

    xDelta = targetX - xPos;
    yDelta = targetY - yPos;

    // find target angle
    let targetAngle = Math.atan(yDelta/xDelta);
    if (isNaN(targetAngle)) targetAngle = 0;
    if (xDelta < 0) targetAngle = Math.PI*.5 - (targetAngle*-1);
    else targetAngle = -((targetAngle*-1) - Math.PI*1.5);
    
    // find shortest rotation delta
    let aAngle = angle;
    let aTargetAngle = targetAngle;
    if (aTargetAngle > aAngle && aTargetAngle - aAngle > Math.PI) {
        aAngle += Math.PI;
        aTargetAngle -= Math.PI;
    } else if (aAngle > aTargetAngle  && aAngle - aTargetAngle > Math.PI) {
        aAngle -= Math.PI;
        aTargetAngle += Math.PI;
    }

    rDelta = aTargetAngle - aAngle;

    // console.log(`myAngle: ${angle * (180 / Math.PI)} target angle: ${targetAngle * (180 / Math.PI)}`)
    // console.log(`deelta: ${(rDelta) * (180 / Math.PI)} `);

    // apply delta
    angle += rDelta * turnSpeedCoeff;

    // counter overflow
    if (angle > 2*Math.PI) angle -= 2*Math.PI;
    else if (angle < 0) angle += 2*Math.PI;

    // stop when close
    let dist = Math.sqrt((xPos-targetX)**2 + (yPos-targetY)**2);
    brake = dist < brakeDist;
    if (!brake) {
        accel = accelCurve(dist);
        if (accel > maxAccel) accel = maxAccel;
        else if (accel < -maxAccel) accel = -maxAccel;
    } else accel = 0;

    // physics
    velocity += accel * deltaT;

    if (brake) {
        // basic friction
        velocity *= slideFric;
    }

    // vel limit
    if (velocity > maxVel) velocity = maxVel;
    else if (velocity < -maxVel) velocity = -maxVel

    // translate vector to 2D
    let hAngle = angle % Math.PI;
    let right = angle > Math.PI;
    let xVel = Math.sin(hAngle) * velocity;
    let yVel = Math.cos(hAngle) * velocity;
    if (right) {
        yVel *= -1;
    }  else {
        xVel *= -1;
    }

    // apply velocity
    xPos += xVel * deltaT;
    yPos += yVel * deltaT;

    // bounce duck at edge of screen
    if (xPos > document.scrollingElement.scrollWidth - duckSize) {
        xPos = document.scrollingElement.scrollWidth - duckSize;
        angle = 2*Math.PI - angle;
    } else if (xPos < 0) {
        xPos = 0;
        angle = 2*Math.PI - angle;
    }
    if (yPos > document.scrollingElement.scrollHeight - duckSize) {
        yPos = document.scrollingElement.scrollHeight - duckSize;
        angle = Math.PI - angle;
    } else if (yPos < 0) {
        yPos = 0;
        angle = Math.PI - angle;
    }

    // limit angle again
    if (angle > 2*Math.PI) angle -= 2*Math.PI;
    else if (angle < 0) angle += 2*Math.PI;

    // console.log(`accel: ${accel}`);
    // console.log(`velocity: ${velocity} (${xVel}, ${yVel})`)

    let visualAngle = angle + (rDelta/2);
    visualAngle = targetAngle;

    thing.style.left = xPos + 'px';
    thing.style.top = yPos + 'px';
    // thing.style.rotate = visualAngle + 'rad';
    // if (brake) {
    //     thing.style['background-color'] = '#00ff00';
    // } else {
    //     thing.style['background-color'] = '#ff0000';
    // }

    let tAngle = visualAngle + Math.PI/4;
    if (tAngle < Math.PI/2 || tAngle > Math.PI * 2) {
        // front-facing
        thing.style['background-position-x'] = (2*duckSize) + 'px';
    } else if (tAngle < Math.PI) {
        // left-facing
        thing.style['background-position-x'] = '0px';
    } else if (tAngle < Math.PI*3/2) {
        // right-facing
        thing.style['background-position-x'] = (3*duckSize) + 'px';
    } else {
        // back-facing
        thing.style['background-position-x'] = duckSize + 'px';
    }

    if (thisUpdate - lastAlt > 70) {
        lastAlt = thisUpdate;
        alt = !alt;
    }
    
    if (velocity > 50) {
        thing.style['background-position-y'] = (duckSize * (alt + 1)) + 'px';
    } else {
        thing.style['background-position-y'] = '0px';
    }

}

// scroll and mouse are separate so the cursor is followed when scrolled
document.addEventListener('mousemove', e => {
    mouseX = e.clientX;
    mouseY = e.clientY;
});

document.addEventListener('scroll', e => {
    el = e.target.scrollingElement;
    scrollX = el.scrollLeft;
    scrollY = el.scrollTop;
});

// kick-start duck
let duck_start = false;
function click_duck() {
    if (duck_start) return;
    duck_start = true;

    xPos = thing.offsetLeft;
    yPos = thing.offsetTop;
    thing.style.position = 'absolute';
    thing.style.cursor = 'auto';
    lastUpdate = Date.now();
    
    updateTimerId = setInterval(update, 10);
}

