<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Driving Prototype - Tight Physics</title>

<link href="https://unpkg.com/maplibre-gl@3.6.2/dist/maplibre-gl.css" rel="stylesheet">

<style>
  html, body {
    margin: 0;
    padding: 0;
    overflow: hidden;
    height: 100%;
    background: #000;
  }
  #map {
    position: absolute;
    inset: 0;
  }
  #overlay {
    position: absolute;
    inset: 0;
    pointer-events: none;
  }
</style>
</head>
<body>

<div id="map"></div>
<canvas id="overlay"></canvas>

<script src="https://unpkg.com/maplibre-gl@3.6.2/dist/maplibre-gl.js"></script>

<script>
/* ---------------- CONFIG ---------------- */
const START_LNG = 173.28463;
const START_LAT = -41.27011;
const START_ZOOM = 19;
const START_PITCH = 45;

/* ---------------- STATE ---------------- */
let map;
let canvas, ctx;

let player = {
  lng: START_LNG,
  lat: START_LAT,
  heading: 0,
  speed: 0,
  maxSpeed: 25,
  accel: 12,
  brake: 18,
  friction: 8
};

const keys = { w:false, s:false, a:false, d:false };

let lastTime = performance.now();

/* Camera */
let cameraBearing = 0;
let followEnabled = true;

/* RMB camera rotate */
let isRightDragging = false;
let lastMouseX = 0;

/* ---------------- INPUT ---------------- */
window.addEventListener("keydown", e => {
  if (e.key === "w") keys.w = true;
  if (e.key === "s") keys.s = true;
  if (e.key === "a") keys.a = true;
  if (e.key === "d") keys.d = true;
});

window.addEventListener("keyup", e => {
  if (e.key === "w") keys.w = false;
  if (e.key === "s") keys.s = false;
  if (e.key === "a") keys.a = false;
  if (e.key === "d") keys.d = false;
});

window.addEventListener("mousedown", e => {
  if (e.button === 2) {
    isRightDragging = true;
    followEnabled = false;
    lastMouseX = e.clientX;
  }
});

window.addEventListener("mousemove", e => {
  if (isRightDragging) {
    const dx = e.clientX - lastMouseX;
    lastMouseX = e.clientX;
    cameraBearing += dx * 0.25;
  }
});

window.addEventListener("mouseup", e => {
  if (e.button === 2) {
    isRightDragging = false;
    followEnabled = true;
  }
});

window.addEventListener("contextmenu", e => e.preventDefault());

/* ---------------- INIT ---------------- */
window.onload = () => {
  map = new maplibregl.Map({
    container: 'map',
    style: 'https://api.maptiler.com/maps/019d3452-4395-7ecd-bbf0-c64a3d5060cd/style.json?key=uHmPABwBFcVhiPJcdCzb',
    center: [START_LNG, START_LAT],
    zoom: START_ZOOM,
    pitch: START_PITCH,
    bearing: 0
  });

  map.keyboard.disable();
  map.dragRotate.disable();
  map.touchZoomRotate.disableRotation();

  canvas = document.getElementById("overlay");
  ctx = canvas.getContext("2d");
  resizeCanvas();
  window.addEventListener("resize", resizeCanvas);

  cameraBearing = player.heading;

  map.on("render", gameLoop);
};

/* ---------------- MAIN LOOP ---------------- */
function gameLoop() {
  const now = performance.now();
  const dt = (now - lastTime) / 1000;
  lastTime = now;

  updatePlayer(dt);
  updateCamera();
  renderOverlay();
}

/* ---------------- PLAYER MOVEMENT ---------------- */
function updatePlayer(dt) {
  // Accel / brake
  if (keys.w) player.speed += player.accel * dt;
  if (keys.s) player.speed -= player.brake * dt;

  // Clamp
  if (player.speed > player.maxSpeed) player.speed = player.maxSpeed;
  if (player.speed < -player.maxSpeed * 0.5) player.speed = -player.maxSpeed * 0.5;

  // Friction
  if (!keys.w && !keys.s) {
    if (player.speed > 0) player.speed -= player.friction * dt;
    if (player.speed < 0) player.speed += player.friction * dt;
    if (Math.abs(player.speed) < 0.1) player.speed = 0;
  }

  // Turning only when moving
  if (Math.abs(player.speed) > 0.1) {
    const turnRate = 60 * (player.speed / player.maxSpeed); // speed-based turning
    if (keys.a) player.heading -= turnRate * dt;
    if (keys.d) player.heading += turnRate * dt;
  }

  // Movement in world space
  const rad = player.heading * Math.PI / 180;
  const dx = Math.cos(rad) * player.speed * dt;
  const dy = Math.sin(rad) * player.speed * dt;

  const p = map.project([player.lng, player.lat]);
  const newPoint = { x: p.x + dx, y: p.y + dy };
  const ll = map.unproject(newPoint);

  player.lng = ll.lng;
  player.lat = ll.lat;
}

/* ---------------- CAMERA FOLLOW ---------------- */
function updateCamera() {
  map.setCenter([player.lng, player.lat]);

  if (followEnabled && !isRightDragging) {
    cameraBearing = lerpAngle(cameraBearing, player.heading, 0.25);
  }

  map.setBearing(cameraBearing);
}

/* ---------------- RENDER CAR ---------------- */
function renderOverlay() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  const cx = canvas.width / 2;
  const cy = canvas.height / 2;

  ctx.save();
  ctx.translate(cx, cy);

  const visualAngle = (player.heading - cameraBearing) * Math.PI / 180;
  ctx.rotate(visualAngle);

  const w = 20;
  const h = 32;

  ctx.fillStyle = "#fff";
  ctx.strokeStyle = "#00eaff";
  ctx.lineWidth = 2;

  ctx.beginPath();
  ctx.moveTo(0, -h/2);
  ctx.lineTo(w/2, h/2);
  ctx.lineTo(0, h/4);
  ctx.lineTo(-w/2, h/2);
  ctx.closePath();
  ctx.fill();
  ctx.stroke();

  ctx.restore();
}

/* ---------------- UTILS ---------------- */
function resizeCanvas() {
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
}

function lerpAngle(a, b, t) {
  let diff = ((b - a + 540) % 360) - 180;
  return a + diff * t;
}
</script>

</body>
</html>
