const module = document.querySelector("div#SKF-Planning-Module");

// Get the canvas element and its context
const canvas = document.querySelector("#SKF-Planning-canvas");
const ctx = canvas.getContext("2d");

// Get the inputs
const angleInputSlider = document.querySelector("#SKF-Planning-angleInputSlider");
const angleInputManual = document.querySelector("#SKF-Planning-angleInputManual");
const lengthInputSlider = document.querySelector("#SKF-Planning-lengthInputSlider");
const lengthInputManual = document.querySelector("#SKF-Planning-lengthInputManual");
const thicknessInput = document.querySelector("#SKF-Planning-thicknessInput");
const addButton = document.querySelector("#SKF-Planning-addLineButton");
const scaleUpButton = document.querySelector("#SKF-Planning-scaleup");
const scaleDownButton = document.querySelector("#SKF-Planning-scaledown");
const pathInput = document.querySelector("#SKF-Planning-pathInput");
const materialInput = document.querySelector("#SKF-Planning-materialInput");

const lineSeparator = document.querySelector("#SKF-Planning-Options #lineSep");

const deleteHeader = document.querySelector("#SKF-Planning-Delete-Head");
const addToCartButton = document.querySelector("#SKF-Planning-addtocart");


let angleInput = 0;
let lengthInput = 0;

let scale = 1;

let path = [{ length: 100, angle: 0 },{ length: 1, angle: 180 }]; // initializes path with a horizontal line
let lastPoint = { x:0, y:0};
let angle = 180;

let isDragging = false;
let lastX = 0;
let lastY = 0;

let thickness = thicknessInput.value;
let material = materialInput.value;

// Add event listeners to the scale buttons
scaleUpButton.addEventListener("click", scaleUp);
scaleDownButton.addEventListener("click", scaleDown);

// Add an event listener to update the size when the window is resized
window.addEventListener("resize", updateCanvasSize);

// Add event listeners to the inputs values so they are updated when the slider is moved or the value is manually changed
angleInputSlider.addEventListener("input", function() {
  angleInputManual.value = angleInputSlider.value;
});
angleInputManual.addEventListener("input", function() {
  angleInputSlider.value = angleInputManual.value;
});
lengthInputSlider.addEventListener("input", function() {
  lengthInputManual.value = lengthInputSlider.value
});
lengthInputManual.addEventListener("input", function() {
  lengthInputSlider.value = lengthInputManual.value;
});

// Add event listeners to the selected material properties
thicknessInput.addEventListener("input", function() {
  thickness = thicknessInput.value;
  drawPath(path);
  updateTempLine(); 
});

materialInput.addEventListener("input", function() {
  material = materialInput.value;
  drawPath(path);
  updateTempLine();
});

// Add event listeners to the inputs
angleInputSlider.addEventListener("input", updateTempLine);
angleInputManual.addEventListener("input", updateTempLine);
lengthInputSlider.addEventListener("input", updateTempLine);
lengthInputManual.addEventListener("input", updateTempLine);

// Add a button to add a point to the path
addButton.addEventListener("click", addPoint);

// Add event listeners to the canvas for mouse events to pan the canvas
canvas.addEventListener("mousedown", e => {
  canvas.style.cursor = "grabbing";
  document.body.style.cursor = "grabbing";
  isDragging = true;
  lastX = e.clientX;
  lastY = e.clientY;
});

window.addEventListener("mousemove", e => {
  if (isDragging) {
    e.preventDefault();
    const deltaX = e.clientX - lastX;
    const deltaY = e.clientY - lastY;
    ctx.translate(deltaX, deltaY);
    drawPath(path);
    updateTempLine();
    lastX = e.clientX;
    lastY = e.clientY;
  }
});

window.addEventListener("mouseup", e => {
  canvas.style.cursor = "grab";
  document.body.style.cursor = "initial";
  isDragging = false;
});

// Add event listeners to the canvas for touch events to pan the canvas
canvas.addEventListener("touchstart", e => {
  isDragging = true;
  lastX = e.touches[0].clientX;
  lastY = e.touches[0].clientY;
});

window.addEventListener("touchmove", e => {
  if (isDragging) {    
    e.preventDefault();
    const deltaX = e.touches[0].clientX - lastX;
    const deltaY = e.touches[0].clientY - lastY;
    ctx.translate(deltaX, deltaY);
    clearCanvas();
    drawPath(path);
    updateTempLine();
    lastX = e.touches[0].clientX;
    lastY = e.touches[0].clientY;
  }
}, {passive: false});

window.addEventListener("touchend", e => {
  isDragging = false;
});

// Add event listener to add lines with the enter key
window.addEventListener("keypress", function(event) {  
  if (isModuleInView() && event.keyCode == 13) {
    event.preventDefault();
    addPoint();
  }
});

// Add event listeners to the inputs values
window.addEventListener("keydown", function(event) {
  if (isModuleInView()){
    switch (event.keyCode) {
      case 37: // Left arrow
        event.preventDefault();
        angleInputSlider.value = parseInt(angleInputSlider.value) - 1;
        angleInputManual.value = angleInputSlider.value;
        updateTempLine();
        break;
      case 38: // Up arrow
        event.preventDefault();
        lengthInputSlider.value = parseInt(lengthInputSlider.value) + 1;
        lengthInputManual.value = lengthInputSlider.value;
        updateTempLine();
        break;
      case 39: // Right arrow
        event.preventDefault();
        angleInputSlider.value = parseInt(angleInputSlider.value) + 1;
        angleInputManual.value = angleInputSlider.value;
        updateTempLine();
        break;
      case 40: // Down arrow
        event.preventDefault();
        lengthInputSlider.value = parseInt(lengthInputSlider.value) - 1;
        lengthInputManual.value = lengthInputSlider.value;
        updateTempLine();
        break;
      case 107: // Numpad +
        event.preventDefault();
        scaleUp();
        break;
      case 109: // Numpad -
        event.preventDefault();
        scaleDown();
        break;
      default:
        break;
    }
  }  
});

// Checks if the canvas is in full view
function isModuleInView() {
  const rect = canvas.getBoundingClientRect();
  return (
    rect.top >= 0 &&
    rect.left >= 0 &&
    rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
    rect.right <= (window.innerWidth || document.documentElement.clientWidth)
  );
}

// Function to update the temporary line on the canvas
function updateTempLine() {
  ctx.save();
  angleInput = parseFloat(angleInputSlider.value);
  lengthInput = parseInt(lengthInputSlider.value);
  const drawAngle = (angleInput + angle) * Math.PI / 180; // Convert angle to radians
  const length = lengthInput;
  const x = lastPoint.x + length * Math.cos(drawAngle);
  const y = lastPoint.y + length * Math.sin(drawAngle);
  clearCanvas();
  drawPath(path); // Draw the existing path
  ctx.beginPath();
  ctx.strokeStyle = "red"; // Set the stroke style to red
  ctx.lineWidth = thickness;
  ctx.moveTo(lastPoint.x, lastPoint.y);
  ctx.lineTo(x, y);
  ctx.stroke(); // Draw the temporary line
  ctx.restore();
}

// Function to add a point to the path
function addPoint() {
  angle += angleInput; // Convert angle to radians
  const length = lengthInput;
  const x = lastPoint.x + length * Math.cos(angle * Math.PI / 180);
  const y = lastPoint.y + length * Math.sin(angle * Math.PI / 180);
  lastPoint = { x, y };
  const point = { length: length, angle: angleInput };
  path.push(point);
  drawPath(path);
  angleInputManual.value = 0;
  angleInputSlider.value = 0;
  updateTempLine();
  populatePathTable();
}

// Function to draw a path
function drawPath(path) {
  clearCanvas();
  ctx.save();
  ctx.beginPath();  
  ctx.lineCap = "round";
  ctx.strokeStyle = material; // Set the stroke style to black  
  ctx.lineWidth = thickness;
  let recentPoint = {x: 0, y:0};
  let totalAngle = 0;
  let lastAngle = 0;
  for (let i = 0; i < path.length; i++) {
    totalAngle += path[i].angle; // Adds the angle to the total angle to determind the angle of the line
    lastAngle = path[i].angle;
    let x = recentPoint.x + path[i].length * Math.cos(totalAngle * Math.PI / 180);
    let y = recentPoint.y + path[i].length * Math.sin(totalAngle * Math.PI / 180);
    ctx.lineTo(x, y);
    recentPoint = {x, y};
    lastPoint = {x, y};
  }
  ctx.stroke();
  ctx.restore();
}

function populatePathTable() {
  pathInput.innerHTML = ""; // Clear the table
  for (let i = 2; i < path.length; i++) {    // Goes thru every user inputted point
    deleteHeader.style.display = "initial";
    const row = document.createElement("tr");
    const pointCell = document.createElement("td");
    pointCell.textContent = i - 1; // Set the point number to the order in which the user inputted it
    const lengthCell = document.createElement("td");
    const lengthInput = document.createElement("input");
    lengthInput.type = "number";
    lengthInput.value = path[i].length;
    lengthInput.onchange = function() {
      path[i].length = parseFloat(this.value);
      drawPath(path);
      updateTempLine();
    };
    lengthCell.appendChild(lengthInput);
    const angleCell = document.createElement("td");
    const angleInput = document.createElement("input");
    angleInput.type = "number";
    angleInput.value = path[i].angle;
    angleInput.onchange = function() {
      path[i].angle = parseFloat(this.value);
      recalculateAngels();
      drawPath(path);
      updateTempLine();
    };
    angleCell.appendChild(angleInput);
    const deleteCell = document.createElement("td");
    deleteCell.innerHTML = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"currentColor\" class=\"bi bi-trash-fill\" viewBox=\"0 0 16 16\"><path d=\"M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1H2.5zm3 4a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5zM8 5a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7A.5.5 0 0 1 8 5zm3 .5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 1 0z\"/></svg>"
    deleteCell.onclick = removeLine.bind(this, i);
    deleteCell.className = "SKF-Planning-DeleteRow";
    row.appendChild(pointCell);
    row.appendChild(lengthCell);
    row.appendChild(angleCell);
    row.appendChild(deleteCell);
    pathInput.appendChild(row);
  }
}

// Function to remove a point from the path
function removeLine(lineNum){
  deleteHeader.style.display = "none";
  path.splice(lineNum, 1);
  recalculateAngels();
  drawPath(path);
  updateTempLine();
  populatePathTable();
}

// Function to remove all angels from the path
function recalculateAngels() {
  angle = 0;
  for (let i = 0; i < path.length; i++) {
    angle += path[i].angle;
  }
}

// Function to update the canvas size
function updateCanvasSize() {
  canvas.width = Math.min((0.85 * canvas.parentElement.clientWidth) - 10, 40 * parseFloat(getComputedStyle(document.documentElement).fontSize)); // Set the width to 95% of the window width or 50 times the font size, whichever is smaller
  canvas.height = Math.min(canvas.width * 13 / 22, 20 * parseFloat(getComputedStyle(document.documentElement).fontSize)); // Set the height based on the aspect ratio or 20 times the font size, whichever is smaller
  positionCanvas();
  setupLineSep();
}

// Scales up the canvas by 1.1x and redraws the path
function scaleUp() {
  scale *= 1.1;
  ctx.scale(1.1, 1.1);
  drawPath(path);
  updateTempLine();
}

// Scales down the canvas by 0.9x and redraws the path
function scaleDown() {
  scale *= 0.9;
  ctx.scale(0.9, 0.9);
  drawPath(path);
  updateTempLine();
}

// Positions the canvas in the center of the screen
function positionCanvas() {
  ctx.setTransform(1, 0, 0, 1, 0, 0); // Reset the transformation matrix
  ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear the canvas
  ctx.translate(ctx.canvas.width / 2, ctx.canvas.height - 65);
  ctx.save();
  drawPath(path);
  updateTempLine();
}

// Function to clear the canvas
function clearCanvas() {
  ctx.save(); // Save the current state of the canvas context
  ctx.setTransform(1, 0, 0, 1, 0, 0); // Reset the transformation matrix
  ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear the canvas
  ctx.restore(); // Restore the saved state of the canvas context
}

// Function to draw the line separator for the options menu
function setupLineSep() {
  width = 1;
  height = 0.8;
  verticalWidth = 0.95;
  const rect = lineSeparator.parentElement.querySelector(".SKF-Planning-Options-Line").getBoundingClientRect();
  if (window.innerWidth >= 850) {
    lineSeparator.style.width = width + "px";
    lineSeparator.style.height = height * 100 + "%";
    lineSeparator.style.left = ((lineSeparator.parentElement.clientWidth / 2) - (width / 2)) + "px";
    lineSeparator.style.top = (lineSeparator.parentElement.clientHeight - lineSeparator.parentElement.clientHeight * height) / 2 + "px";
  } 
  else{
    lineSeparator.style.height = width + "px";
    lineSeparator.style.width = verticalWidth * 100 + "%";
    lineSeparator.style.left = (lineSeparator.parentElement.clientWidth - lineSeparator.parentElement.clientWidth * verticalWidth) / 2 + "px";
    lineSeparator.style.top = ((rect.height + 1 * parseFloat(getComputedStyle(document.documentElement).fontSize)) + (width / 2)) + "px";
  }
}

updateTempLine(); // Call the function once to draw the initial line
updateCanvasSize(); // Call the function once to set the initial size
positionCanvas(); // Call the function once to position the canvas
populatePathTable(); // Call the function once to populate the path table
setupLineSep(); // Sets up the line separator of the line selectors