// for some reason it isn't showing that you are dragging a fruit when dragging
// from one cell to another. it actually is dragging but it doesn't show it
// this is a helper to create a drag image so it shows the fruit being dragged
function createDragImage(el) {
  const dragImg = el.cloneNode(true);
  dragImg.style.position = 'absolute';
  dragImg.style.top = '-1000px';
  dragImg.style.left = '-1000px';
  document.body.appendChild(dragImg);
  return dragImg;
}

// helper to place a fruit div inside a square div
function placeFruitInSquare(squareEl, fruitName) {
  // clear existing content
  squareEl.innerHTML = '';
  // record the fruit in the square for tracking
  squareEl.dataset.fruit = fruitName;
  // find the template fruit in the palette
  const template = document.querySelector(`.fruit[data-fruit="${fruitName}"]`);
  if (!template) return;
  // clone and drop
  const clone = template.cloneNode(true);
  clone.classList.remove('fruit');         // remove extra styling if you like
  clone.classList.add('dropped-fruit');
  clone.setAttribute('draggable', true);     // allow repositioning if desired
  
  // add drag start for dragging from a square
  clone.addEventListener('dragstart', e => {
    e.dataTransfer.setData('text/plain', fruitName);
    const dragImg = createDragImage(clone);
    e.dataTransfer.setDragImage(dragImg, dragImg.offsetWidth / 2, dragImg.offsetHeight / 2);
    clone.addEventListener('dragend', () => {
      dragImg.remove();
    }, { once: true });
  });
  
  squareEl.appendChild(clone);

  // add X clear button
  const clearBtn = document.createElement('button');
  clearBtn.classList.add('clear-btn');
  clearBtn.textContent = 'X';
  clearBtn.addEventListener('click', async (e) => {
    e.stopPropagation(); // prevent event bubbling
    squareEl.innerHTML = '';
    delete squareEl.dataset.fruit;
    const squareId = squareEl.dataset.squareId;
    await fetch('/api/positions', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ squareId, fruit: '' }),
    });
  });
  squareEl.appendChild(clearBtn);
}

// initialize drag & drop on fruits
document.querySelectorAll('.fruit').forEach(el => {
  el.addEventListener('dragstart', e => {
    e.dataTransfer.setData('text/plain', el.dataset.fruit);
    const dragImg = createDragImage(el);
    e.dataTransfer.setDragImage(dragImg, dragImg.offsetWidth / 2, dragImg.offsetHeight / 2);
    // cleanup after drag
    el.addEventListener('dragend', () => {
      dragImg.remove();
    }, { once: true });
  });
  
  // updated mouseover event
  el.addEventListener('mouseover', e => {
    const parentCategory = el.closest('.categories');
    if (parentCategory) {
      // Unhighlight all squares for fruits in this category first
      parentCategory.querySelectorAll('.fruit').forEach(sib => {
        const sq = document.querySelector(`.square[data-fruit="${sib.dataset.fruit}"]`);
        if (sq) sq.classList.remove('highlight');
      });
    }
    // Now highlight only the hovered fruit's square
    const square = document.querySelector(`.square[data-fruit="${el.dataset.fruit}"]`);
    if (square) square.classList.add('highlight');
    updateHighlightedBorders();
  });
  
  // updated mouseout event
  el.addEventListener('mouseout', e => {
    // Remove highlight from the hovered fruit's square
    const square = document.querySelector(`.square[data-fruit="${el.dataset.fruit}"]`);
    if (square) square.classList.remove('highlight');
    // If still inside the category container, restore highlighting to all fruits there
    const parentCategory = el.closest('.categories');
    if (parentCategory && parentCategory.contains(e.relatedTarget)) {
      parentCategory.querySelectorAll('.fruit').forEach(sib => {
        const sq = document.querySelector(`.square[data-fruit="${sib.dataset.fruit}"]`);
        if (sq) sq.classList.add('highlight');
      });
    }
    updateHighlightedBorders();
  });
});

// make each square a drop target
document.querySelectorAll('.square').forEach(sq => {
  sq.addEventListener('dragover', e => e.preventDefault());
  sq.addEventListener('drop', async e => {
    e.preventDefault();
    const fruit = e.dataTransfer.getData('text/plain');

    // check if the fruit is already placed in another square
    const existingSquare = document.querySelector(`.square[data-fruit="${fruit}"]`);
    if (existingSquare && existingSquare !== sq) {
      existingSquare.innerHTML = '';
      delete existingSquare.dataset.fruit;
      const existingSquareId = existingSquare.dataset.squareId;
      await fetch('/api/positions', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ squareId: existingSquareId, fruit: '' }),
      });
    }

    placeFruitInSquare(sq, fruit);

    // save to server
    const squareId = sq.dataset.squareId;
    await fetch('/api/positions', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ squareId, fruit }),
    });
  });
});

// on load, fetch saved positions and render
window.addEventListener('DOMContentLoaded', async () => {
  try {
    const res = await fetch('/api/positions');
    const mapping = await res.json();
    for (const [squareId, fruit] of Object.entries(mapping)) {
      const sq = document.querySelector(
        `.square[data-square-id="${squareId}"]`
      );
      if (sq && fruit) {
        placeFruitInSquare(sq, fruit);
      }
    }
  } catch (err) {
    console.error('Could not load saved positions', err);
  }
});

// this is the stuff that let's you drag the map around and zoom in and out
(() => {
  const mapWrapper = document.getElementById('mapWrapper');
  const map = document.getElementById('map');
  let isDragging = false;
  let startX, startY, startPanX, startPanY;
  let panX = 0, panY = 0;
  let currentScale = 1;
  const minScale = 0.5, maxScale = 3;

  function updateTransform() {
    map.style.transform = `translate(${panX}px, ${panY}px) scale(${currentScale})`;
  }

  mapWrapper.addEventListener('mousedown', (e) => {
    if (e.target.closest('.fruit') || e.target.closest('.dropped-fruit')) return;
    isDragging = true;
    startX = e.clientX;
    startY = e.clientY;
    startPanX = panX;
    startPanY = panY;
    map.style.cursor = 'grabbing';
  });

  document.addEventListener('mousemove', (e) => {
    if (!isDragging) return;
    const deltaX = e.clientX - startX;
    const deltaY = e.clientY - startY;
    panX = startPanX + deltaX;
    panY = startPanY + deltaY;
    updateTransform();
  });

  document.addEventListener('mouseup', () => {
    if (isDragging) {
      isDragging = false;
      map.style.cursor = 'grab';
    }
  });

  // mouse wheel zoom and smooth zoom
  mapWrapper.addEventListener('wheel', (e) => {
    e.preventDefault();
    const sensitivity = 0.001; // adjust sensitivity of zoom
    // calculate new scale smoothly using exponential curve
    let newScale = currentScale * Math.exp(-e.deltaY * sensitivity);
    // clamp to allowed values
    newScale = Math.min(maxScale, Math.max(minScale, newScale));
    const zoomFactor = newScale / currentScale;
    
    // Get the mouse position relative to the mapWrapper
    const rect = mapWrapper.getBoundingClientRect();
    const offsetX = e.clientX - rect.left;
    const offsetY = e.clientY - rect.top;
    
    // Adjust panX and panY so the zoom is centered on the pointer
    panX = offsetX - zoomFactor * (offsetX - panX);
    panY = offsetY - zoomFactor * (offsetY - panY);
    
    currentScale = newScale;
    updateTransform();
  });

  // new function for smooth zoom animation
  function animateZoom(targetScale, targetPanX, targetPanY, duration = 300) {
    const startScale = currentScale;
    const startPanX = panX;
    const startPanY = panY;
    const startTime = performance.now();
    
    function step(now) {
        const elapsed = now - startTime;
        const progress = Math.min(elapsed / duration, 1); // progress from 0 to 1 (linear easing)
        
        currentScale = startScale + (targetScale - startScale) * progress;
        panX = startPanX + (targetPanX - startPanX) * progress;
        panY = startPanY + (targetPanY - startPanY) * progress;
        updateTransform();
        
        if (progress < 1) {
            requestAnimationFrame(step);
        }
    }
    
    requestAnimationFrame(step);
}

// zoom button handlers using smooth animation
const zoomInBtn = document.getElementById('zoomIn');
const zoomOutBtn = document.getElementById('zoomOut');

const zoomButtonHandler = (zoomFactor) => {
    let targetScale = currentScale * zoomFactor;
    targetScale = Math.min(maxScale, Math.max(minScale, targetScale));
    // calculate the actual zoom factor applied.
    const actualFactor = targetScale / currentScale;
    
    // use the center of the mapWrapper as the zoom origin.
    const rect = mapWrapper.getBoundingClientRect();
    const centerX = rect.width / 2;
    const centerY = rect.height / 2;
    const targetPanX = centerX - actualFactor * (centerX - panX);
    const targetPanY = centerY - actualFactor * (centerY - panY);
    
    animateZoom(targetScale, targetPanX, targetPanY, 300); // change this for the zoom animation time
};

zoomInBtn.addEventListener('click', () => {
    zoomButtonHandler(1.2);
});

zoomOutBtn.addEventListener('click', () => {
    zoomButtonHandler(0.8);
});
})();
  
// add highlighting for squares based on category hover
document.querySelectorAll('.categories').forEach(category => {
  category.addEventListener('mouseenter', () => {
    category.querySelectorAll('.fruit').forEach(fruitEl => {
      const fruitName = fruitEl.dataset.fruit;
      const square = document.querySelector(`.square[data-fruit="${fruitName}"]`);
      if (square) {
        square.classList.add('highlight');
      }
    });
    updateHighlightedBorders();
  });
  category.addEventListener('mouseleave', () => {
    category.querySelectorAll('.fruit').forEach(fruitEl => {
      const fruitName = fruitEl.dataset.fruit;
      const square = document.querySelector(`.square[data-fruit="${fruitName}"]`);
      if (square) {
        square.classList.remove('highlight');
      }
    });
    updateHighlightedBorders();
  });
});

/* 
   this is a helper to update highlighted square borders.
   for each highlighted square, if a neighboring square is also highlighted,
   set the border color on that touching side to transparent.
   this makes it look like the squares are connected.
*/
function updateHighlightedBorders() {
  const squares = document.querySelectorAll('.square');
  squares.forEach(sq => {
    // Reset any inline style if not highlighted
    if (!sq.classList.contains('highlight')) {
      sq.style.borderLeftColor = '';
      sq.style.borderRightColor = '';
      sq.style.borderTopColor = '';
      sq.style.borderBottomColor = '';
      return;
    }
    
    // set all borders to the highlight color. change this to change the color
    sq.style.borderLeftColor = '#d103f9';
    sq.style.borderRightColor = '#d103f9';
    sq.style.borderTopColor = '#d103f9';
    sq.style.borderBottomColor = '#d103f9';
    
    // find the parent row and index
    const parentRow = sq.parentElement; // .map-row
    const cells = Array.from(parentRow.children);
    const idx = cells.indexOf(sq);
    
    // check left neighbor in the same row
    if (idx > 0 && cells[idx - 1].classList.contains('square') && cells[idx - 1].classList.contains('highlight')) {
      sq.style.borderLeftColor = 'transparent';
    }
    // check right neighbor in the same row
    if (idx < cells.length - 1 && cells[idx + 1].classList.contains('square') && cells[idx + 1].classList.contains('highlight')) {
      sq.style.borderRightColor = 'transparent';
    }
    
    // for top and bottom, get the row index from map (#map container)
    const map = parentRow.parentElement;
    const rows = Array.from(map.children);
    const rowIndex = rows.indexOf(parentRow);
    // check top neighbor (like same cell index in previous row)
    if (rowIndex > 0) {
      const topRow = rows[rowIndex - 1];
      const topCells = Array.from(topRow.children);
      if (topCells[idx] && topCells[idx].classList.contains('square') && topCells[idx].classList.contains('highlight')) {
        sq.style.borderTopColor = 'transparent';
      }
    }
    // check bottom neighbor (like same cell index in next row)
    if (rowIndex < rows.length - 1) {
      const bottomRow = rows[rowIndex + 1];
      const bottomCells = Array.from(bottomRow.children);
      if (bottomCells[idx] && bottomCells[idx].classList.contains('square') && bottomCells[idx].classList.contains('highlight')) {
        sq.style.borderBottomColor = 'transparent';
      }
    }
  });
}

// add Socket.io client side for real time updates
const socket = io();

socket.on('update', data => {
  // find the square with the given squareId
  const sq = document.querySelector(`.square[data-square-id="${data.squareId}"]`);
  if (sq) {
    if (data.fruit) {
      if (sq.dataset.fruit !== data.fruit) {
        placeFruitInSquare(sq, data.fruit);
      }
    } else {
      sq.innerHTML = '';
      delete sq.dataset.fruit;
    }
    // add highlight and remove after 3 seconds
    sq.classList.add('highlight-update');
    setTimeout(() => {
      sq.classList.remove('highlight-update');
    }, 1000);
  }
});
