import { Conductor } from "./conductor";

export class Renderer {
  timeIndicator;
  currStaveNumber;
  numStaves;
  sheetWindow;
  eventCanvas;
  ctx;
  canvasWidth;
  canvasHeight;
  iconCache = []; // stores { image, x, y, width, height }
  imageCache = new Map(); // memoized <svgString, HTMLImageElement>

  constructor() {
    this.numStaves = 6;
    this.currStaveNumber = 1;

    this.timeIndicator = document.querySelector("#time-indicator");
    this.sheetWindow = document.getElementById("music-window");

    // Setup canvas
    this.eventCanvas = document.getElementById("event-canvas");
    this.ctx = this.eventCanvas.getContext("2d");

    this.resizeCanvas();
    window.addEventListener("resize", () => {
      this.resizeCanvas();
      this.redrawIcons();
    });

    this.timeIndicator.addEventListener("animationiteration", () => {
      this.currStaveNumber++;
      if (this.currStaveNumber > this.numStaves) {
        this.cleanUpAndRestart();
      }
    });

    // Render stave SVGs
    for (let i = 1; i <= this.numStaves; i++) {
      const staveWrapper = document.createElement("div");
      staveWrapper.classList.add("stave-wrapper");
      staveWrapper.setAttribute("id", `stave-wrapper-${i}`);
      staveWrapper.style.position = "relative";

      const staveObject = document.createElement("object");
      staveObject.type = "image/svg+xml";
      staveObject.data = "assets/svg/stave.svg";
      staveObject.classList.add("stave-svg");

      staveWrapper.appendChild(staveObject);
      this.sheetWindow.appendChild(staveWrapper);
    }
  }

  resizeCanvas() {
    this.canvasWidth = this.sheetWindow.offsetWidth;
    this.canvasHeight = this.sheetWindow.offsetHeight;
    this.eventCanvas.width = this.canvasWidth;
    this.eventCanvas.height = this.canvasHeight;
    console.log("Canvas size:", this.canvasWidth, this.canvasHeight);
  }

  async placeIcon(instrument) {
    if (this.currStaveNumber > this.numStaves) this.currStaveNumber = 1;

    const rect = this.timeIndicator.getBoundingClientRect();
    const sheetLeft = this.sheetWindow.getBoundingClientRect().left;
    const xPosition = rect.left + window.scrollX - sheetLeft;

    const yPercent = parseFloat(instrument.yPos); // e.g., "55%" => 55
    const y = (yPercent / 100) * this.canvasHeight;

    // Handle image caching
    let svgString = instrument.image;
    if (svgString.startsWith("data:image/svg+xml;base64,")) {
      const base64 = svgString.split(",")[1];
      svgString = atob(base64);
    }

    // Ensure SVG has dimensions
    svgString = this.ensureSvgHasDimensions(
      svgString,
      instrument.width || 50,
      instrument.height || 50
    );

    const img = await this.loadImageFromSVG(svgString);

    // Fallback if instrument.width/height not provided
    const naturalWidth = img.naturalWidth || 50;
    const naturalHeight = img.naturalHeight || 50;
    const scale = 0.25;
    const width = parseFloat(instrument.width || naturalWidth) * scale;
    const height = parseFloat(instrument.height || naturalHeight) * scale;

    this.ctx.drawImage(img, xPosition, y, width, height);

    // Store for redrawing later
    this.iconCache.push({
      image: img,
      x: xPosition,
      y,
      width,
      height,
    });

    console.log("Drawing position:", xPosition, y);
    console.log("width", width, "height", height);
    console.log(
      "Canvas size:",
      this.eventCanvas.width,
      this.eventCanvas.height
    );
    console.log(
      "Canvas offset size:",
      this.eventCanvas.offsetWidth,
      this.eventCanvas.offsetHeight
    );
  }
  ensureSvgHasDimensions(svgString, defaultWidth = 50, defaultHeight = 50) {
    const hasWidth = /<svg[^>]*\bwidth=/.test(svgString);
    const hasHeight = /<svg[^>]*\bheight=/.test(svgString);

    if (!hasWidth || !hasHeight) {
      svgString = svgString.replace(
        /<svg([^>]*)>/,
        `<svg width="${defaultWidth}" height="${defaultHeight}"$1>`
      );
    }

    return svgString;
  }

  async loadImageFromSVG(svgString) {
    if (this.imageCache.has(svgString)) {
      return this.imageCache.get(svgString);
    }

    return new Promise((resolve, reject) => {
      const blob = new Blob([svgString], { type: "image/svg+xml" });
      const url = URL.createObjectURL(blob);
      const img = new Image();

      img.onload = () => {
        console.log("Image loaded:", img.width, img.height); // should no longer be 0

        const scale = 0.25;
        const width = instrument.width * scale || img.width * scale;
        const height = instrument.height * scale || img.height * scale;

        ctx.drawImage(img, xPosition, y, width, height);
        URL.revokeObjectURL(url);
      };

      img.onerror = (err) => {
        console.error("Image failed to load from SVG:", err);
        reject(err);
      };

      img.src = url;
    });
  }

  redrawIcons() {
    this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
    this.iconCache.forEach(({ image, x, y, width, height }) => {
      this.ctx.drawImage(image, x, y, width, height);
    });
  }

  cleanUpAndRestart(reload = false) {
    this.iconCache = [];
    this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
    this.currStaveNumber = 1;

    Conductor.setTitle();
    if (reload) location.reload();
  }
}

// This will need to be worked on. There is no need for the loadImageFromSVG function here and the placeIcon function will need to be changed to reflect it.
// image size and z-index isn't correct and the canvas will need to be enlarged to allow icons to overhang the staves.
