---
const { mode = "unsigned", defaultBits = 8 } = Astro.props;

// For unsigned: min 1 bit, max 16 bits (tweak if you want)
const minBits = 4;
const maxBits = 16;
const initialBits = Math.min(Math.max(defaultBits, minBits), maxBits);
---

<section class="binary-sim" data-mode={mode} data-bits={initialBits}>
  <div class="top">
    <div class="left-brand">
      <!-- Replace with your logo/img -->
      <div class="brand-box" aria-hidden="true">Computing:Box</div>
    </div>

    <div class="display" aria-live="polite">
      <div class="label">DENARY</div>
      <div id="denaryNumber" class="value">0</div>

      <div class="label">BINARY</div>
      <div id="binaryNumber" class="value mono">00000000</div>
    </div>

    <div class="actions">
      <button class="btn" type="button" data-action="custom-binary">Custom Binary</button>
      <button class="btn" type="button" data-action="custom-denary">Custom Denary</button>
      <button class="btn" type="button" data-action="shift-left">Left Shift</button>
      <button class="btn" type="button" data-action="shift-right">Right Shift</button>

      <div class="bits-control">
        <div class="bits-title">Bits</div>
        <div class="bits-buttons">
          <button class="btn small" type="button" data-action="bits-minus" aria-label="Decrease bits">−</button>
          <span id="bitsCount" class="bits-count">{initialBits}</span>
          <button class="btn small" type="button" data-action="bits-plus" aria-label="Increase bits">+</button>
        </div>
      </div>
    </div>
  </div>

  <div id="bitsRow" class="bits-row" aria-label="Binary bit switches"></div>
</section>

<script is:inline>
(() => {
  const root = document.currentScript.closest(".binary-sim");
  const bitsRow = root.querySelector("#bitsRow");
  const binaryEl = root.querySelector("#binaryNumber");
  const denaryEl = root.querySelector("#denaryNumber");
  const bitsCountEl = root.querySelector("#bitsCount");

  let bitCount = parseInt(root.dataset.bits || "8", 10);
  const minBits = 4;
  const maxBits = 16;

  // state: array of 0/1, MSB at index 0
  let bits = new Array(bitCount).fill(0);

  function placeValues(n) {
    // unsigned place values: [2^(n-1), ..., 2^0]
    return Array.from({ length: n }, (_, i) => 2 ** (n - 1 - i));
  }

  function bitsToDenary(bitsArr) {
    const pv = placeValues(bitsArr.length);
    return bitsArr.reduce((acc, b, i) => acc + (b ? pv[i] : 0), 0);
  }

  function render() {
    const binaryStr = bits.join("");
    binaryEl.textContent = binaryStr;
    denaryEl.textContent = String(bitsToDenary(bits));
    bitsCountEl.textContent = String(bitCount);

    const pv = placeValues(bitCount);

    bitsRow.innerHTML = pv.map((value, i) => {
      const id = `bit_${bitCount}_${i}`;
      const checked = bits[i] === 1 ? "checked" : "";
      return `
        <div class="bit-col">
          <div class="bulb ${bits[i] ? "on" : "off"}" aria-hidden="true"></div>
          <div class="place">${value}</div>

          <label class="switch" for="${id}">
            <input id="${id}" type="checkbox" ${checked} data-index="${i}">
            <span class="slider" aria-hidden="true"></span>
            <span class="sr-only">Toggle bit value ${value}</span>
          </label>
        </div>
      `;
    }).join("");
  }

  function setBitsFromBinaryString(str) {
    // allow shorter input; pad left
    const clean = (str || "").trim();
    if (!/^[01]+$/.test(clean) || clean.length > bitCount) return false;
    const padded = clean.padStart(bitCount, "0");
    bits = padded.split("").map(c => c === "1" ? 1 : 0);
    return true;
  }

  function setBitsFromDenary(num) {
    if (!Number.isInteger(num)) return false;
    const max = (2 ** bitCount) - 1;
    if (num < 0 || num > max) return false;

    const bin = num.toString(2).padStart(bitCount, "0");
    bits = bin.split("").map(c => c === "1" ? 1 : 0);
    return true;
  }

  function shiftLeft() {
    bits = bits.slice(1).concat(0);
  }

  function shiftRight() {
    bits = [0].concat(bits.slice(0, -1));
  }

  function resizeBits(newCount) {
    const clamped = Math.max(minBits, Math.min(maxBits, newCount));
    if (clamped === bitCount) return;

    // keep value as best as possible: preserve LSBs when resizing
    const currentBinary = bits.join("");
    bitCount = clamped;
    bits = new Array(bitCount).fill(0);

    const take = currentBinary.slice(-bitCount);
    setBitsFromBinaryString(take);
  }

  // Switch input handler
  bitsRow.addEventListener("change", (e) => {
    const input = e.target;
    if (!(input instanceof HTMLInputElement)) return;
    const idx = parseInt(input.dataset.index || "-1", 10);
    if (idx < 0) return;
    bits[idx] = input.checked ? 1 : 0;
    render();
  });

  // Button actions
  root.querySelector(".actions").addEventListener("click", (e) => {
    const btn = e.target.closest("button[data-action]");
    if (!btn) return;

    const action = btn.dataset.action;

    if (action === "custom-binary") {
      const entered = prompt(`Enter a ${bitCount}-bit binary value (0s and 1s):`, bits.join(""));
      if (entered === null) return;
      if (!setBitsFromBinaryString(entered)) {
        alert(`Invalid binary. Use only 0 and 1, up to ${bitCount} digits.`);
        return;
      }
      render();
    }

    if (action === "custom-denary") {
      const max = (2 ** bitCount) - 1;
      const entered = prompt(`Enter a denary value (0 to ${max}):`, String(bitsToDenary(bits)));
      if (entered === null) return;
      const num = Number.parseInt(entered, 10);
      if (!setBitsFromDenary(num)) {
        alert(`Invalid denary. Enter a whole number from 0 to ${max}.`);
        return;
      }
      render();
    }

    if (action === "shift-left") { shiftLeft(); render(); }
    if (action === "shift-right") { shiftRight(); render(); }

    if (action === "bits-minus") { resizeBits(bitCount - 1); render(); }
    if (action === "bits-plus") { resizeBits(bitCount + 1); render(); }
  });

  // initial
  render();
})();
</script>

<style>
/* Layout */
.binary-sim {
  padding: 2rem 1rem 3rem;
}

.top {
  display: grid;
  grid-template-columns: 260px 1fr 220px;
  gap: 1.5rem;
  align-items: start;
}

@media (max-width: 980px) {
  .top {
    grid-template-columns: 1fr;
  }
  .actions {
    display: grid;
    grid-template-columns: 1fr 1fr;
  }
}

/* Brand placeholder */
.brand-box {
  width: 180px;
  height: 180px;
  border-radius: 12px;
  display: grid;
  place-items: center;
  font-weight: 700;
  opacity: 0.9;
  border: 1px solid rgba(255,255,255,0.08);
  background: rgba(255,255,255,0.04);
}

/* Display */
.display {
  text-align: center;
  padding: 1rem;
}

.label {
  letter-spacing: 0.12em;
  opacity: 0.85;
  margin-top: 0.5rem;
}

.value {
  font-size: 3rem;
  line-height: 1.1;
  margin: 0.25rem 0 0.75rem;
  font-weight: 700;
}

.mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}

/* Buttons */
.actions {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.btn {
  border: 0;
  border-radius: 10px;
  padding: 0.75rem 1rem;
  font-weight: 600;
  cursor: pointer;
  background: rgba(255,255,255,0.08);
  color: inherit;
}

.btn:hover { background: rgba(255,255,255,0.12); }

.btn.small {
  padding: 0.45rem 0.75rem;
  border-radius: 10px;
}

.bits-control {
  margin-top: 0.25rem;
  padding-top: 0.5rem;
  border-top: 1px solid rgba(255,255,255,0.08);
}

.bits-title { opacity: 0.8; margin-bottom: 0.35rem; }

.bits-buttons {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.bits-count {
  min-width: 2ch;
  text-align: center;
  font-weight: 700;
}

/* Bits row */
.bits-row {
  margin-top: 2rem;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(88px, 1fr));
  gap: 1.25rem;
  align-items: end;
}

.bit-col {
  text-align: center;
  padding: 0.5rem 0.25rem;
}

.place {
  margin: 0.5rem 0 0.5rem;
  font-size: 2rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}

/* Bulb */
.bulb {
  width: 26px;
  height: 26px;
  margin: 0 auto 0.25rem;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,0.15);
}
.bulb.off { opacity: 0.15; }
.bulb.on  { opacity: 1; }

/* Light switch (accessible checkbox) */
.switch {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 36px;
  position: relative;
}

.switch input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}

.slider {
  width: 64px;
  height: 36px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
  position: relative;
  transition: transform 120ms ease, background 120ms ease;
}

.slider::after {
  content: "";
  position: absolute;
  top: 4px;
  left: 4px;
  width: 28px;
  height: 28px;
  border-radius: 999px;
  background: rgba(255,255,255,0.85);
  transition: transform 120ms ease;
}

.switch input:checked + .slider {
  background: rgba(255,255,255,0.18);
}

.switch input:checked + .slider::after {
  transform: translateX(28px);
}

/* focus */
.switch input:focus-visible + .slider {
  outline: 3px solid rgba(255,255,255,0.35);
  outline-offset: 2px;
}

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0);
  white-space: nowrap; border: 0;
}
</style>
