let predictionsPanel;
const wheelSingleZero = [0, 32, 15, 19, 4, 21, 2, 25, 17, 34, 6, 27, 13, 36, 11,
  30, 8, 23, 10, 5, 24, 16, 33, 1, 20, 14, 31, 9, 22, 18, 29, 7, 28, 12, 35, 3, 26];

const wheelDoubleZero = [0, 28, 9, 26, 30, 11, 7, 20, 32, 17, 5, 22, 34, 15, 3,
  24, 36, 13, 1, 38, 27, 10, 25, 29, 12, 8, 19, 31, 18, 6, 21, 33, 16, 4, 23, 35, 14, 2];

let seenTimestampsByCasino = new Map();

function api_button_on_click_event_old(button) {
  button.addEventListener('click', () => {
    const popup = document.createElement('div');
    popup.classList.add('api-popup');
    popup.style.position = 'fixed';
    popup.style.top = '100px';
    popup.style.left = '100px';
    popup.style.backgroundColor = 'white';
    popup.style.padding = '20px';
    popup.style.border = '1px solid black';
    popup.style.zIndex = 1000;
    popup.style.maxHeight = '80vh';
    popup.style.overflowY = 'auto';

    const closeButton = document.createElement('button');
    closeButton.textContent = 'Close';
    closeButton.style.marginTop = '10px';
    closeButton.addEventListener('click', () => {
      popup.remove();
    });
    popup.appendChild(closeButton);



    const title = document.createElement('h1');
    title.innerText = 'Live Spin Numbers';
    popup.appendChild(title);

    const liveLink = document.createElement('a');
    liveLink.href = 'spins.php';
    liveLink.target = '_blank';
    liveLink.textContent = 'Show Live Numbers';
    liveLink.style.display = 'block';
    liveLink.style.marginTop = '20px';
    popup.appendChild(liveLink);

    const content = document.createElement('div');
    popup.appendChild(content);

    apis.forEach(api => {
      const section = document.createElement('div');
      section.style.marginBottom = '20px';

      const titleContainer = document.createElement('div');
      titleContainer.style.display = 'flex';
      titleContainer.style.justifyContent = 'space-between';
      titleContainer.style.alignItems = 'center';

      const title = document.createElement('h2');
      title.textContent = api.name;

      const refreshEntryButton = document.createElement('button');
      refreshEntryButton.textContent = 'Refresh';
      refreshEntryButton.style.marginLeft = '10px';
      refreshEntryButton.addEventListener('click', async () => {
        try {
          const response = await fetch(api.file);
          if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
          const updatedData = await response.json();
          const updatedNumbers = updatedData
            .map(entry => entry.data?.result?.outcome?.number)
            .filter(n => typeof n === 'number')
            .join(', ');

          const textbox = document.getElementById(`textbox-${api.name}`);
          if (textbox) {
            textbox.value = updatedNumbers;
          }
        } catch (error) {
          console.error(`Failed to refresh data for ${api.name}:`, error);
        }
      });

      titleContainer.appendChild(title);
      titleContainer.appendChild(refreshEntryButton);

      const textbox = document.createElement('textarea');
      textbox.id = `textbox-${api.name}`;
      textbox.style.width = '100%';
      textbox.style.height = '80px';
      textbox.style.marginTop = '10px';
      textbox.placeholder = 'Click Refresh to load data';

      const logButton = document.createElement('button');
      logButton.textContent = 'Add All Numbers to the Tool';
      logButton.style.marginTop = '10px';
      logButton.addEventListener('click', () => {
        applyAPI(api.name);
      });



      const manualAddText = document.createElement('span');
      manualAddText.textContent = 'Add all numbers once, then manually add numbers with the keypad on the right side of the roulette board.';
      manualAddText.style.display = 'block';
      manualAddText.style.marginTop = '5px';

      section.appendChild(titleContainer);
      section.appendChild(textbox);
      section.appendChild(logButton);
      section.appendChild(manualAddText);

      content.appendChild(section);
    });



    document.body.appendChild(popup);

    // Make popup draggable
    makeDraggable(popup);

  });
}

function api_button_on_click_event(button) {
  button.addEventListener('click', () => {
    const popup = document.createElement('div');
    popup.style.position = 'fixed';
    popup.style.top = '120px';
    popup.style.left = '120px';
    popup.style.backgroundColor = 'white';
    popup.style.padding = '20px';
    popup.style.border = '1px solid black';
    popup.style.zIndex = '9999';
    popup.style.overflow = 'visible';
    popup.style.maxHeight = 'none';
    popup.style.pointerEvents = 'auto';

    const headerContainer = document.createElement('div');
    headerContainer.style.display = 'flex';
    headerContainer.style.justifyContent = 'space-between';
    headerContainer.style.alignItems = 'center';
    headerContainer.style.marginBottom = '10px';

    const closeButton = document.createElement('button');
    closeButton.textContent = 'Close';
    closeButton.addEventListener('click', () => popup.remove());

const howToLink = document.createElement('div');
howToLink.textContent = 'After selecting casino, Click the fetch button then Hold the Spin All Numbers button down until all numbers have been added Be patient please. Use the autospin button below for more options';
howToLink.style.marginLeft = '10px';
howToLink.style.alignSelf = 'center';
howToLink.style.fontSize = '14px';
howToLink.style.color = '#555'; // Optional: soft gray to show it's a note
howToLink.style.maxWidth = '300px';
howToLink.style.lineHeight = '1.2';

    headerContainer.appendChild(closeButton);
    headerContainer.appendChild(howToLink);
    popup.appendChild(headerContainer);

    const liveLink = document.createElement('a');
    liveLink.href = 'https://gamble-galaxy.com/spins.php';
    liveLink.target = '_blank';
    liveLink.textContent = 'Show Live Numbers';
    liveLink.style.display = 'block';
    liveLink.style.marginTop = '20px';
    popup.appendChild(liveLink);

    const title = document.createElement('h1');
    title.innerText = 'Casino Number Fetcher';
    popup.appendChild(title);

    const dropdown = document.createElement('select');
    dropdown.style.width = '100%';
    dropdown.style.marginBottom = '10px';
    dropdown.style.padding = '5px';
    dropdown.style.fontSize = '16px';
    dropdown.style.overflow = 'visible';



    // Default disabled option
const defaultOption = document.createElement('option');
defaultOption.value = '';
defaultOption.textContent = 'Select Casino';
defaultOption.disabled = false; // ✅ Important
defaultOption.selected = true;  // ✅ Makes it default
dropdown.appendChild(defaultOption);

    apis.forEach(api => {
      const option = document.createElement('option');
      option.value = api.file;
      option.textContent = api.name;
      dropdown.appendChild(option);
    });

        const dropdownContainer = document.createElement('div');
dropdownContainer.style.overflow = 'visible';
dropdownContainer.appendChild(dropdown);
popup.appendChild(dropdownContainer);

dropdown.addEventListener('change', () => {
  if (dropdown.value === '') {
    // Clear the textbox
    textbox.value = '';

    // Stop auto-fetch
    if (fetchInterval) {
      clearInterval(fetchInterval);
      fetchInterval = null;
    }

    // (Optional) Clear seenTimestamps
  // if (dropdown.value && seenTimestampsByCasino.has(dropdown.value)) {
  //seenTimestampsByCasino.set(dropdown.value, new Set());
//}
  }


});


    const textbox = document.createElement('textarea');
    textbox.style.width = '100%';
    textbox.style.height = '80px';
    textbox.placeholder = 'Click Fetch to load data';
    popup.appendChild(textbox);


    let fetchInterval = null;

    async function fetchNumbersFromSelectedFile() {
      if (!dropdown.value) return;

      try {
        const file = dropdown.value;
        const response = await fetch(file);
        if (!response.ok) throw new Error(`HTTP error! Status: ${response.status}`);
        const data = await response.json();

        const newNumbers = [];

        for (const entry of data) {
          const ts = entry.data?.settledAt;
          const number = entry.data?.result?.outcome?.number;

if (!seenTimestampsByCasino.has(file)) {
  seenTimestampsByCasino.set(file, new Set());
}
const seenSet = seenTimestampsByCasino.get(file);


if (ts && !seenSet.has(ts) && typeof number === 'number') {
  seenSet.add(ts);
  newNumbers.push(number);
}
        }

        if (newNumbers.length > 0) {
          const existingNumbers = textbox.value
            .split(',')
            .map(n => n.trim())
            .filter(n => n !== '')
            .map(n => parseInt(n, 10));

          const updatedNumbers = newNumbers.concat(existingNumbers);
          textbox.value = updatedNumbers.join(', ');
        } else {
          console.log('No new spins found.');
        }

      } catch (err) {
        console.error('Fetch error:', err);
      }
    }

    const fetchButton = document.createElement('button');
    fetchButton.textContent = 'Fetch Numbers from Casino';
    fetchButton.style.marginTop = '10px';
    fetchButton.addEventListener('click', () => {
      if (!dropdown.value) {
        alert('Please select a casino from the dropdown first.');
        return;
      }

      fetchNumbersFromSelectedFile();

      if (!fetchInterval) {
        fetchInterval = setInterval(fetchNumbersFromSelectedFile, 15000); // every 15 sec
      }
    });
    popup.appendChild(fetchButton);

    const addOneButton = document.createElement('button');
    addOneButton.textContent = 'Spin One Number';
    addOneButton.style.marginTop = '10px';
    addOneButton.style.marginLeft = '10px';

addOneButton.addEventListener('click', async () => {
 
  const values = textbox.value.split(',').map(v => v.trim()).filter(v => v !== '');
  if (values.length === 0) return;

  const last = parseInt(values.pop());
  if (!isNaN(last)) numberPadSpin(last);
  textbox.value = values.join(', ');

  addOneButton.disabled = true;


      setTimeout(() => {
      addOneButton.disabled = false;
      addOneButton.textContent = 'Spin One Number';
    }, 500);
});



    // Add All Numbers Button
const addAllButton = document.createElement('button');
addAllButton.textContent = 'Spin All Numbers';
addAllButton.style.marginTop = '10px';
addAllButton.style.marginLeft = '10px';
addAllButton.style.position = 'relative';
addAllButton.style.overflow = 'hidden';
addAllButton.style.width = '250px';
addAllButton.style.height = '36px';

// Progress overlay
const progressOverlay = document.createElement('div');
progressOverlay.style.position = 'absolute';
progressOverlay.style.top = '0';
progressOverlay.style.left = '0';
progressOverlay.style.height = '100%';
progressOverlay.style.width = '0%';
progressOverlay.style.backgroundColor = 'hsl(59, 92.90%, 55.90%)';
progressOverlay.style.transition = 'width 0s'; // we'll animate it manually

addAllButton.appendChild(progressOverlay);
popup.appendChild(addAllButton);

// Logic for hold-to-activate
let holdTimer = null;
let holdProgress = 0;
let holdInterval = null;
const holdDuration = 2000; // 2 seconds
const tickRate = 50; // ms

addAllButton.addEventListener('mousedown', () => {
  holdProgress = 0;
  progressOverlay.style.width = '0%';

  holdInterval = setInterval(() => {
    holdProgress += tickRate;
    const percent = Math.min((holdProgress / holdDuration) * 100, 100);
    progressOverlay.style.width = percent + '%';

    if (holdProgress >= holdDuration) {
      clearInterval(holdInterval);
      progressOverlay.style.width = '100%';

      // Add all numbers
const values = textbox.value.split(',').map(v => v.trim()).filter(v => v !== '');
for (const value of values.reverse()) {
  const number = parseInt(value);
  if (!isNaN(number)) numberPadSpin(number);
}
textbox.value = '';

      // Clear the textbox
      textbox.value = '';

      // Reset progress
      setTimeout(() => {
        progressOverlay.style.width = '0%';
      }, 500);
    }
  }, tickRate);
});

addAllButton.addEventListener('mouseup', () => {
  clearInterval(holdInterval);
  progressOverlay.style.width = '0%';
});

addAllButton.addEventListener('mouseleave', () => {
  clearInterval(holdInterval);
  progressOverlay.style.width = '0%';
});

    popup.appendChild(addOneButton);

// ADD FILE
// Spacer
const spacer = document.createElement('div');
spacer.style.marginTop = '20px';
popup.appendChild(spacer);

// Container for import + reverse
const importRow = document.createElement('div');
importRow.style.display = 'flex';
importRow.style.gap = '10px';
popup.appendChild(importRow);

// Import File Button
const importButton = document.createElement('button');
importButton.textContent = 'Import Numbers from Text File';
importButton.style.flex = '1';
importRow.appendChild(importButton);

// Reverse Button
const reverseButton = document.createElement('button');
reverseButton.textContent = 'Reverse Numbers in Textbox';
reverseButton.style.flex = '1';
importRow.appendChild(reverseButton);

// File input (hidden)
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = '.txt';
fileInput.style.display = 'none';
document.body.appendChild(fileInput);

// Handle file selection
importButton.addEventListener('click', () => {
  fileInput.click();
});

fileInput.addEventListener('change', () => {
  const file = fileInput.files[0];
  if (!file) return;

  const reader = new FileReader();
  reader.onload = function (e) {
    const content = e.target.result;

    // Extract numbers between 0 and 38
    const numbers = content
      .split(/[^0-9]+/) // split by anything that's not a digit
      .map(n => parseInt(n, 10))
      .filter(n => !isNaN(n) && n >= 0 && n <= 38);

    // Update the textbox
    textbox.value = numbers.join(', ');
  };

  // ✅ Stop fetching and reset dropdown
  if (fetchInterval) {
    clearInterval(fetchInterval);
    fetchInterval = null;
  }
  dropdown.selectedIndex = 0;

  reader.readAsText(file);
});

// Reverse button logic
reverseButton.addEventListener('click', () => {
  const reversed = textbox.value
    .split(',')
    .map(n => n.trim())
    .filter(n => n !== '')
    .reverse();

  textbox.value = reversed.join(', ');
});



    document.body.appendChild(popup);
    ai_makeDraggable(popup);
  });
}


function applyAPI(name) {
  const textbox = document.getElementById(`textbox-${name}`);
  if (textbox && textbox.value.trim() !== '') {
    const numbers = textbox.value
      .split(',')
      .map(n => parseInt(n.trim()))
      .filter(n => !isNaN(n))
      .reverse(); // Reverse the order before applying

    if (Array.isArray(numbers)) {
      numbers.forEach(num => {
        // Assume numberPadSpin is your function that processes each number
        numberPadSpin(num);
      });
    }
  }
}


function makeDraggable(elmnt) {
  let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
  elmnt.onmousedown = dragMouseDown;

  function dragMouseDown(e) {
    e = e || window.event;
    e.preventDefault();
    pos3 = e.clientX;
    pos4 = e.clientY;
    document.onmouseup = closeDragElement;
    document.onmousemove = elementDrag;
  }

  function elementDrag(e) {
    e = e || window.event;
    e.preventDefault();
    pos1 = pos3 - e.clientX;
    pos2 = pos4 - e.clientY;
    pos3 = e.clientX;
    pos4 = e.clientY;
    elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
    elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
  }

  function closeDragElement() {
    document.onmouseup = null;
    document.onmousemove = null;
  }
}
//-----------------------------------------------------------------------------------------------------------------------------------
// AI Section
//------------------------------------------------------------------------------------------------------------------------------------

function getWheelNeighbors(number, wheelLayout) {
  const index = wheelLayout.findIndex(n => n === number || (n === '00' && number === 37));
  if (index === -1) return [];

  const neighbors = [];
  for (let i = -3; i <= 3; i++) {
    let neighborIndex = (index + i + wheelLayout.length) % wheelLayout.length;
    neighbors.push(wheelLayout[neighborIndex]);
  }
  return neighbors;
}



function getOutsideBet(n) {
  const red = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36];
  const black = [2, 4, 6, 8, 10, 11, 13, 15, 17, 20, 22, 24, 26, 28, 29, 31, 33, 35];

  return {
    color: red.includes(n) ? 'Red' : black.includes(n) ? 'Black' : 'Green',
    oddEven: n === 0 ? 'None' : n % 2 === 0 ? 'Even' : 'Odd',
    highLow: n === 0 ? 'None' : n <= 18 ? 'Low (1-18)' : 'High (19-36)',
    dozen: n === 0 ? 'None' : n <= 12 ? '1st Dozen' : n <= 24 ? '2nd Dozen' : '3rd Dozen',
    column: n === 0 ? 'None' : n % 3 === 1 ? '1st Column' : n % 3 === 2 ? '2nd Column' : '3rd Column',
  };
}


function ai_button_click_event(button) {
  button.addEventListener('click', () => {
    const popup = document.createElement('div');
    popup.style.position = 'fixed';
    popup.style.top = '120px';
    popup.style.left = '120px';
    popup.style.backgroundColor = 'white';
    popup.style.padding = '20px';
    popup.style.border = '1px solid black';
    popup.style.zIndex = '9999';         // keep it above everything
    popup.style.overflow = 'visible';    // allow dropdowns to overflow
    popup.style.maxHeight = 'none';      // remove clipping
    popup.style.pointerEvents = 'auto';  // ensure interaction

const headerContainer = document.createElement('div');
headerContainer.style.display = 'flex';
headerContainer.style.justifyContent = 'space-between';
headerContainer.style.alignItems = 'center';
headerContainer.style.marginBottom = '10px';

// Close Button
const closeButton = document.createElement('button');
closeButton.textContent = 'Close';
closeButton.addEventListener('click', () => popup.remove());

// How To Link
const howToLink = document.createElement('a');
howToLink.href = 'AI_how_to.pdf'; // update with your actual how-to URL
howToLink.target = '_blank';
howToLink.textContent = 'How To';
howToLink.style.marginLeft = '10px';
howToLink.style.textDecoration = 'none';
howToLink.style.alignSelf = 'center';

// Add both to the header container
headerContainer.appendChild(closeButton);
headerContainer.appendChild(howToLink);

// Append the header to the popup
popup.appendChild(headerContainer);


   const aiOneButton = document.createElement('button');
aiOneButton.textContent = 'AI Predict';
aiOneButton.style.marginTop = '10px';
aiOneButton.style.marginLeft = '10px';
aiOneButton.style.fontSize = '18px';
aiOneButton.style.padding = '12px 24px';
aiOneButton.style.fontWeight = 'bold';

popup.appendChild(aiOneButton);

// Warning message element (hidden by default)
const warningMessage = document.createElement('div');
warningMessage.textContent = 'Predictions need at least 50 spins';
warningMessage.style.color = 'red';
warningMessage.style.marginTop = '10px';
warningMessage.style.fontWeight = 'bold';
warningMessage.style.display = 'none'; // hidden initially
popup.appendChild(warningMessage);

// Predict button click logic
aiOneButton.addEventListener('click', async () => {
  if (!predictionsPanel) return;

  // Check if the numbers array has fewer than 50 elements
  if (!Array.isArray(numbers) || numbers.length < 50) {
    warningMessage.style.display = 'block';
    return;
  } else {
    warningMessage.style.display = 'none';
  }

  aiOneButton.disabled = true;
  aiOneButton.textContent = 'Predicting...';

  try {
    const newPanel = await get_ai_predictions_with_model();
    predictionsPanel.replaceWith(newPanel);
    predictionsPanel = newPanel;
  } catch (err) {
    console.error('Prediction failed:', err);
  }

  aiOneButton.disabled = false;
  aiOneButton.textContent = 'AI Predict';
});



    const predictionsTitle = document.createElement('h2');
    predictionsTitle.textContent = 'AI Predictions';
    predictionsTitle.style.marginTop = '20px';
    popup.appendChild(predictionsTitle);

    // Get content from your prediction function
    predictionsPanel = get_ai_predictions();
    popup.appendChild(predictionsPanel);


    document.body.appendChild(popup);
    ai_makeDraggable(popup);
  });





}

/*
function ai_makeDraggable(dragHandle, dragTarget) {
  let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
  dragHandle.onmousedown = dragMouseDown;

  function dragMouseDown(e) {
    e.preventDefault();
    pos3 = e.clientX;
    pos4 = e.clientY;
    document.onmouseup = closeDragElement;
    document.onmousemove = elementDrag;
  }

  function elementDrag(e) {
    e.preventDefault();
    pos1 = pos3 - e.clientX;
    pos2 = pos4 - e.clientY;
    pos3 = e.clientX;
    pos4 = e.clientY;
    dragTarget.style.top = (dragTarget.offsetTop - pos2) + "px";
    dragTarget.style.left = (dragTarget.offsetLeft - pos1) + "px";
  }

  function closeDragElement() {
    document.onmouseup = null;
    document.onmousemove = null;
  }
}
*/
function ai_makeDraggable(elmnt) {
  let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;

  elmnt.onmousedown = function (e) {
    e = e || window.event;

    // Prevent drag if clicking on an interactive element
    const tag = e.target.tagName.toLowerCase();
    if (['select', 'input', 'textarea', 'button', 'label'].includes(tag)) {
      return; // Do not initiate drag
    }

    e.preventDefault();
    pos3 = e.clientX;
    pos4 = e.clientY;
    document.onmouseup = closeDragElement;
    document.onmousemove = elementDrag;
  };

  function elementDrag(e) {
    e = e || window.event;
    e.preventDefault();
    pos1 = pos3 - e.clientX;
    pos2 = pos4 - e.clientY;
    pos3 = e.clientX;
    pos4 = e.clientY;
    elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
    elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
  }

  function closeDragElement() {
    document.onmouseup = null;
    document.onmousemove = null;
  }
}


function get_ai_predictions() {
  const panel = document.createElement('div');
  panel.style.border = '1px solid #ccc';
  panel.style.padding = '10px';
  panel.style.marginTop = '10px';
  panel.style.backgroundColor = '#f9f9f9';

  if (!Array.isArray(numbers) || numbers.length < 10) {
    panel.textContent = 'Not enough data for AI predictions.';
    return panel;
  }

  // --- Basic prediction logic ---
  const last10 = numbers.slice(-10);

  // Method 1: Frequency (most common in last 20)
  const freqMap = {};
  numbers.slice(-20).forEach(n => {
    freqMap[n] = (freqMap[n] || 0) + 1;
  });
  const mostFreq = Object.entries(freqMap).sort((a, b) => b[1] - a[1])[0][0];

  // Method 2: Momentum (last 3 different numbers shifted)
  const momentumGuess = (last10[last10.length - 1] + 3) % 37;

  // Method 3: "Neural Net" stub - avg + noise
  const avg = Math.round(last10.reduce((sum, n) => sum + n, 0) / last10.length);
  const neuralNetGuess = (avg + Math.floor(Math.random() * 5) - 2) % 37;

  // --- Outside Bets ---
  function getOutsideBet(n) {
    const red = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36];
    const black = [2, 4, 6, 8, 10, 11, 13, 15, 17, 20, 22, 24, 26, 28, 29, 31, 33, 35];
    return {
      color: red.includes(n) ? 'Red' : black.includes(n) ? 'Black' : 'Green',
      oddEven: n === 0 ? 'None' : n % 2 === 0 ? 'Even' : 'Odd',
      highLow: n === 0 ? 'None' : n <= 18 ? 'Low (1-18)' : 'High (19-36)',
      dozen: n === 0 ? 'None' : n <= 12 ? '1st Dozen' : n <= 24 ? '2nd Dozen' : '3rd Dozen',
      column: n === 0 ? 'None' : n % 3 === 1 ? '1st Column' : n % 3 === 2 ? '2nd Column' : '3rd Column',
    };
  }
  /*
    // --- Format predictions ---
    const methods = [
      { name: 'Neural Network (avg+noise)', number: neuralNetGuess },
      { name: 'Frequency Analysis', number: parseInt(mostFreq) },
      { name: 'Momentum Shift', number: momentumGuess }
    ];
  
    methods.forEach(method => {
      const bets = getOutsideBet(method.number);
      const section = document.createElement('div');
      section.innerHTML = `
        <strong>${method.name}</strong><br>
        Predicted Number: <b>${method.number}</b><br>
        Outside Bets: ${bets.color}, ${bets.oddEven}, ${bets.highLow}, ${bets.dozen}, ${bets.column}
        <hr>
      `;
      panel.appendChild(section);
    });
  */
  return panel;
}

//-----------------------------------------------------------------------------------------------------------------------------------
// AI TENSOR FLOW
//------------------------------------------------------------------------------------------------------------------------------------


function trainAdaptiveClassifier(numbers, type, minLookback = 3, maxLookback = 6) {
  const red = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36];
  const black = [2, 4, 6, 8, 10, 11, 13, 15, 17, 20, 22, 24, 26, 28, 29, 31, 33, 35];

  const getClassLabel = (n) => {
    switch (type) {
      case 'color': return red.includes(n) ? 'Red' : black.includes(n) ? 'Black' : 'Green';
      case 'evenodd': return n === 0 ? 'None' : n % 2 === 0 ? 'Even' : 'Odd';
      case 'highlow': return n === 0 ? 'None' : n <= 18 ? 'Low' : 'High';
      case 'dozen': return n === 0 ? 'None' : n <= 12 ? '1st' : n <= 24 ? '2nd' : '3rd';
      case 'column': return n === 0 ? 'None' : n % 3 === 1 ? '1st' : n % 3 === 2 ? '2nd' : '3rd';
      default: return n.toString();
    }
  };

  const best = {
    lookback: 0,
    prediction: 'Unknown',
    confidence: 0
  };

  for (let lookback = minLookback; lookback <= maxLookback; lookback++) {
    const sequences = {};

    for (let i = 0; i < numbers.length - lookback; i++) {
      const history = numbers.slice(i, i + lookback).map(getClassLabel).join('-');
      const nextLabel = getClassLabel(numbers[i + lookback]);
      if (!sequences[history]) sequences[history] = {};
      sequences[history][nextLabel] = (sequences[history][nextLabel] || 0) + 1;
    }

    const recent = numbers.slice(-lookback).map(getClassLabel).join('-');
    const possible = sequences[recent];
    if (!possible) continue;

    const total = Object.values(possible).reduce((a, b) => a + b, 0);
    const [prediction, count] = Object.entries(possible).sort((a, b) => b[1] - a[1])[0];
    const confidence = count / total;

    if (confidence > best.confidence) {
      best.lookback = lookback;
      best.prediction = prediction;
      best.confidence = confidence;
    }
  }

return {
  prediction: best.prediction,
  confidence: best.confidence, // ✅ keep it as a raw number (0.843 etc.)
  lookback: best.lookback
};
}



async function trainRouletteModel(numbers, lookback = 5) {
  if (numbers.length <= lookback) return null;

  const xs = [];
  const ys = [];

  for (let i = 0; i < numbers.length - lookback; i++) {
    const input = numbers.slice(i, i + lookback).map(n => n / 36);
    const output = numbers[i + lookback];
    xs.push(input);
    ys.push(output);
  }

  const xsTensor = tf.tensor2d(xs);
  const ysTensor = tf.tensor1d(ys, 'int32');
  const ysOneHot = tf.oneHot(ysTensor, 37);

  const model = tf.sequential();
  model.add(tf.layers.dense({ inputShape: [lookback], units: 32, activation: 'relu' }));
  model.add(tf.layers.dropout({ rate: 0.3 }));
  model.add(tf.layers.dense({ units: 64, activation: 'relu' }));
  model.add(tf.layers.dropout({ rate: 0.3 }));
  model.add(tf.layers.dense({ units: 37, activation: 'softmax' }));

  model.compile({
    optimizer: 'adam',
    loss: 'categoricalCrossentropy',
    metrics: ['accuracy']
  });

  await model.fit(xsTensor, ysOneHot, {
    epochs: 20,
    batchSize: 8,
    shuffle: true
  });

  return model;
}



async function predictNextNumber(model, numbers) {
  const lookback = 5;
  const recent = numbers.slice(-lookback).map(n => n / 36);
  const input = tf.tensor2d([recent]);
  const prediction = model.predict(input);
  const result = prediction.argMax(-1).dataSync()[0];
  return result; // predicted number 0-36
}


function getWheelBiasPrediction(numbers, wheelLayout) {
  if (numbers.length < 50) return null; // not enough data

  // Count hits per number
  const freqMap = Array(37).fill(0);
  for (const n of numbers) {
    if (typeof n === 'number' && n >= 0 && n <= 36) {
      freqMap[n]++;
    }
  }



  // Project frequency onto wheel positions as rolling clusters
  const wheelBiasScores = wheelLayout.map((number, i) => {
    let score = 0;
    for (let j = -2; j <= 2; j++) {
      const neighborIndex = (i + j + wheelLayout.length) % wheelLayout.length;
      const neighbor = wheelLayout[neighborIndex];
      if (typeof neighbor === 'number' && neighbor >= 0 && neighbor <= 36) {
        score += freqMap[neighbor];
      }
    }
    return { number, score };
  });

  // Sort clusters by total score
  wheelBiasScores.sort((a, b) => b.score - a.score);

  // Check if top score is significantly higher than average
  const avgScore = wheelBiasScores.reduce((sum, obj) => sum + obj.score, 0) / wheelBiasScores.length;
  const top = wheelBiasScores[0];

  if (top.score < avgScore + 1) {
    return null; // No strong bias found
  }

  return top.number;
}


function detectDealerSignature(numbers, wheelLayout) {
  if (numbers.length < 15) return null;

  const offsets = [];

  for (let i = 1; i < numbers.length; i++) {
    const prev = numbers[i - 1];
    const curr = numbers[i];
    const prevIndex = wheelLayout.indexOf(prev);
    const currIndex = wheelLayout.indexOf(curr);
    if (prevIndex === -1 || currIndex === -1) continue;

    // Alternate spin direction assumption
    let offset;
    if (i % 2 === 0) {
      // Even-indexed spin = clockwise
      offset = (currIndex - prevIndex + wheelLayout.length) % wheelLayout.length;
    } else {
      // Odd-indexed spin = counter-clockwise
      offset = (prevIndex - currIndex + wheelLayout.length) % wheelLayout.length;
    }

    offsets.push(offset);
  }

  // Count how often each offset appears
  const offsetCounts = {};
  offsets.forEach(off => offsetCounts[off] = (offsetCounts[off] || 0) + 1);

  const sortedOffsets = Object.entries(offsetCounts).sort((a, b) => b[1] - a[1]);
  const [mostCommonOffset, count] = sortedOffsets[0];
  const total = offsets.length;
  const percent = (count / total) * 100;

  if (percent >= 30) {
    // Predict next spin direction
    const lastNumber = numbers[numbers.length - 1];
    const lastIndex = wheelLayout.indexOf(lastNumber);
    const nextDirection = (numbers.length % 2 === 0) ? 'cw' : 'ccw';

    let predictedIndex;
    if (nextDirection === 'cw') {
      predictedIndex = (lastIndex + parseInt(mostCommonOffset)) % wheelLayout.length;
    } else {
      predictedIndex = (lastIndex - parseInt(mostCommonOffset) + wheelLayout.length) % wheelLayout.length;
    }

    const predictedNumber = wheelLayout[predictedIndex];

    return {
      offset: parseInt(mostCommonOffset),
      confidence: percent.toFixed(1),
      predictedNumber,
      direction: nextDirection,
      zone: getWheelNeighbors(predictedNumber, wheelLayout)
    };
  }

  return null;
}

async function get_ai_predictions_with_model() {
  const panel = document.createElement('div');
  panel.innerHTML = '<b>Training AI model...</b>';

  if (!Array.isArray(numbers) || numbers.length < 20) {
    panel.innerHTML = 'Not enough data for AI training.';
    return panel;
  }

  const lookback = 5;
  const testSplit = 0.2;
  const splitIndex = Math.floor(numbers.length * (1 - testSplit));

  const trainNums = numbers.slice(0, splitIndex);
  const testNums = numbers.slice(splitIndex);

  const model = await trainRouletteModel(trainNums);
  const predictedNumber = await predictNextNumber(model, testNums);

  const probs = model.predict(tf.tensor2d([testNums.slice(-lookback).map(n => n / 36)]));
  const confidences = await probs.data();
  const topConfidence = confidences[predictedNumber];
  const outside = getOutsideBet(predictedNumber);

  const locations = [
    ['Number', predictedNumber, (topConfidence * 100).toFixed(1) + '%'],
    ['Color', outside.color, '—'],
    ['Even/Odd', outside.oddEven, '—'],
    ['High/Low', outside.highLow, '—'],
    ['Dozen', outside.dozen, '—'],
    ['Column', outside.column, '—'],
  ];

  // Create prediction table
  const info = document.createElement('div');
  info.innerHTML = `
    <b>Training Samples:</b> ${trainNums.length} <br>
    <b>Test Samples:</b> ${testNums.length}<br><br>
    </table>
  `;
  panel.innerHTML = '';
  panel.appendChild(info);

  // --- Enhanced Wheel Bias with Spin Direction ---
  const lastNumber = numbers[numbers.length - 1];
  const lastIndex = wheelSingleZero.indexOf(lastNumber);

  const biasResult = getWheelBiasPrediction(numbers, wheelSingleZero);
  if (biasResult !== null && lastIndex !== -1) {
    const offset = wheelSingleZero.indexOf(biasResult) - lastIndex;

    const cwIndex = (lastIndex + offset + wheelSingleZero.length) % wheelSingleZero.length;
    const ccwIndex = (lastIndex - offset + wheelSingleZero.length) % wheelSingleZero.length;

    const cwNumber = wheelSingleZero[cwIndex];
    const ccwNumber = wheelSingleZero[ccwIndex];

    const cwZone = getWheelNeighbors(cwNumber, wheelSingleZero);
    const ccwZone = getWheelNeighbors(ccwNumber, wheelSingleZero);

    const cwBets = getOutsideBet(cwNumber);
    const ccwBets = getOutsideBet(ccwNumber);

    const classifiers = ['color', 'evenodd', 'highlow', 'dozen', 'column'];
    const results = [];

for (const type of classifiers) {
  const result = trainAdaptiveClassifier(numbers, type, 4, 6);


  let scaledConfidence = result.confidence;
  if (typeof scaledConfidence !== 'number' || isNaN(scaledConfidence)) {
    scaledConfidence = '—';
  } else {
    scaledConfidence = Math.min(Math.max((scaledConfidence * 100).toFixed(1), 50), 95) + '%';
  }

  results.push([
    type.charAt(0).toUpperCase() + type.slice(1),
    result.prediction,
    scaledConfidence,
    result.lookback
  ]);
}
    // Add number prediction to the top of the results array
    results.unshift(['Number', predictedNumber, (topConfidence * 100).toFixed(1) + '%', lookback]);

    panel.innerHTML += `
  <h3>AI Predictions (Adaptive Pattern Matching)</h3>
  <table border="1" style="width: 100%; text-align: center; border-collapse: collapse;">
    <thead>
      <tr><th>Location</th><th>Prediction</th><th>Confidence</th><th>Pattern Used</th></tr>
    </thead>
    <tbody>
      ${results.map(([loc, pred, conf, lookback]) =>
      `<tr><td>${loc}</td><td>${pred}</td><td>${conf}</td><td>Last ${lookback}</td></tr>`
    ).join('')}
    </tbody>
  </table>
`;



    panel.innerHTML += `<br><strong>Dealer Signature Prediction (Ball Spin Direction Analysis)</strong><br>
    <u>Assuming Clockwise (CW)</u><br>
    Predicted Number: <b>${cwNumber}</b><br>
    Zone (±2): ${cwZone.join(', ')}<br>
    Outside Bets: ${cwBets.color}, ${cwBets.oddEven}, ${cwBets.highLow}, ${cwBets.dozen}, ${cwBets.column}<br><br>

    <u>Assuming Counter-Clockwise (CCW)</u><br>
    Predicted Number: <b>${ccwNumber}</b><br>
    Zone (±2): ${ccwZone.join(', ')}<br>
    Outside Bets: ${ccwBets.color}, ${ccwBets.oddEven}, ${ccwBets.highLow}, ${ccwBets.dozen}, ${ccwBets.column}<br>
  `;
  } else {
    panel.innerHTML += `<br><strong>Wheel Bias Prediction</strong><br>No strong bias detected.<br>`;
  }


  // --- Add Dealer Signature for Single Zero ---
  const dealerSig = detectDealerSignature(numbers, wheelSingleZero);
  if (dealerSig) {
    panel.innerHTML += `<br><strong>Dealer Signature Detected (Single-Zero)</strong><br>
      Offset: <b>${dealerSig.offset}</b><br>
      Confidence: <b>${dealerSig.confidence}%</b><br>
      Direction: ${dealerSig.direction}<br>
      Prediction: <b>${dealerSig.predictedNumber}</b><br>
      Zone: ${dealerSig.zone.join(', ')}<br>`;
  }

  return panel;
}
