<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>𝐓𝐇𝐄 𝐒𝐏𝐘 𝐏𝐑𝐄𝐃𝐈𝐂𝐓𝐎𝐑</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
  <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&family=Orbitron:wght@500;600&display=swap" rel="stylesheet">
  <script src="https://cdn.tailwindcss.com"></script>
  
    @keyframes bounce { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.2); } }
    @keyframes shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(2px); } 50% { transform: translateX(-2px); } 75% { transform: translateX(2px); } }
    @keyframes dash { 0% { stroke-dashoffset: 10; } 100% { stroke-dashoffset: 0; } }
    @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
    @keyframes gradientShift { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } }
    @keyframes ripple { 0% { transform: scale(0); opacity: 0.4; } 100% { transform: scale(4); opacity: 0; } }

    .ripple-button, .ripple {
      position: relative;
      overflow: hidden;
      transition: transform 0.2s ease, box-shadow 0.2s ease;
    }
    .ripple-button:hover, .ripple:hover {
      transform: translateY(-2px);
      box-shadow: 0 8px 20px rgba(0, 255, 255, 0.3);
    }
    .ripple-button:active, .ripple:active {
      transform: scale(0.98);
    }
    .ripple-button::after, .ripple::after {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background: rgba(0, 255, 255, 0.3);
      border-radius: 50%;
      transform: scale(0);
      opacity: 0;
      pointer-events: none;
      z-index: 1;
    }
    .ripple-button.ripple-effect::after, .ripple.ripple-effect::after {
      animation: ripple 0.5s ease-out;
    }

    body {
      background: linear-gradient(to right, #0a0e1a, #1a0a3a, #0a1a0e);
      background-size: 200% 200%;
      animation: gradientShift 15s ease infinite;
      overflow-x: hidden;
      font-family: 'Poppins', sans-serif;
    }

    .wrapper svg {
      width: 100%;
      height: 100%;
      max-height: 50px;
    }
    .wrapper svg text {
      stroke: #00FFFF;
      font-size: 10px;
      font-family: 'Orbitron', sans-serif;
      fill: #FFD700;
      stroke-width: 1;
      animation: dash 2.5s linear infinite;
      text-shadow: 0 0 10px rgba(0, 255, 255, 0.5);
    }

    .win-animation { animation: bounce 0.5s ease-in-out infinite; }
    .loss-animation { animation: shake 0.5s ease-in-out; }
    .spinner { animation: spin 1s linear infinite; }

    .toast {
      position: fixed;
      top: 90px;
      right: 18px;
      left: 18px;
      background: rgba(0, 0, 0, 0.8);
      color: #00FFFF;
      padding: 12px 14px;
      border-radius: 8px;
      border: 1px solid #00FFFF;
      opacity: 0;
      transition: opacity 0.3s ease;
      z-index: 1000;
      box-shadow: 0 0 10px rgba(0, 255, 255, 0.3);
      font-size: 0.75rem;
    }
    .toast.show { opacity: 1; }

    .card {
      background: linear-gradient(145deg, #1a1a2e, #252540);
      border-radius: 12px;
      border: 1px solid rgba(0, 255, 255, 0.3);
      transition: transform 0.3s ease, box-shadow 0.3s ease;
      padding: 0.5rem;
      margin-bottom: 0.75rem;
    }
    .card:hover {
      transform: translateY(-4px);
      box-shadow: 0 10px 20px rgba(0, 255, 255, 0.2);
    }

    .gradient-button {
      background: linear-gradient(to right, #00FFFF, #FF00FF);
      border: none;
      border-radius: 10px;
      padding: 0.375rem 0.75rem;
      font-size: 0.75rem;
      text-transform: uppercase;
      letter-spacing: 1px;
      box-shadow: 0 0 10px rgba(0, 255, 255, 0.3);
      transition: all 0.3s ease;
    }
    .gradient-button:hover {
      background: linear-gradient(to right, #FF00FF, #00FFFF);
      box-shadow: 0 0 15px rgba(0, 255, 255, 0.5);
      transform: translateY(-2px);
    }

    .history-item {
      background: linear-gradient(145deg, #1a1a2e, #252540);
      border-radius: 10px;
      transition: all 0.3s ease;
      padding: 0.5rem;
    }
    .history-item:hover {
      transform: translateY(-2px);
      box-shadow: 0 6px 12px rgba(0, 255, 255, 0.15);
    }

    @media (max-width: 640px) {
      .container { padding: 0 0.25rem; }
      .wrapper svg text { font-size: 16px; }
      .card { padding: 0.375rem; }
      .toast { top: 60px; }
    }
  
</head>
<body class="text-gray-200 font-poppins min-h-screen p-4">
  <div class="container max-w-md mx-auto space-y-6">
    <div class="wrapper">
      <svg role="img" viewBox="0 0 100 29" preserveAspectRatio="xMidYMid meet">
        <text x="50%" y="50%" dy=".1em" text-anchor="middle" font-size="80">
          𝐓𝐇𝐄 𝐒𝐏𝐘 𝐏𝐑𝐄𝐃𝐈𝐂𝐓𝐎𝐑
        </text>
      </svg>
    </div>

    <div class="card shadow-lg">
      <div class="flex items-center justify-between mb-2">
        <h2 class="text-lg font-bold text-cyan-400 flex items-center font-orbitron">
          <i class="fa-solid fa-brain mr-2"></i> Current Predictor
        </h2>
        <button onclick="refreshPrediction()" class="ripple-button gradient-button text-white font-semibold rounded-lg flex items-center">
          <i class="fa-solid fa-sync-alt mr-1"></i> Refresh
        </button>
      </div>
      <div class="bg-gray-900 rounded-lg p-3 text-center">
        <div class="text-cyan-300 mb-2 text-sm">PERIOD: <span id="currentPeriodDisplay">-</span></div>
        <div class="text-cyan-300 mb-2 text-sm">TIMER: <span id="timerDisplay">0 0 : 0 0</span></div>
        <div id="currentPredictionDisplay" class="text-xl font-bold text-cyan-200 mb-1">-</div>
        <div class="text-cyan-200 text-sm">CONFIDENCE: <span id="confidenceDisplay">0%</span></div>
      </div>
    </div>

    <div class="card shadow-lg">
      <h2 class="text-lg font-bold text-cyan-400 mb-2 font-orbitron">═══✿ Analysis Dashboard ✿═══</h2>
      <div class="grid grid-cols-2 gap-2">
        <div class="bg-gray-900 rounded-lg p-3 text-center">
          <div class="text-cyan-400 text-sm">Total Wins</div>
          <div id="totalWins" class="text-lg font-bold text-magenta-400">0</div>
        </div>
        <div class="bg-gray-900 rounded-lg p-3 text-center">
          <div class="text-cyan-300 text-sm">Total Losses</div>
          <div id="totalLosses" class="text-lg font-bold text-magenta-400">0</div>
        </div>
        <div class="bg-gray-900 rounded-lg p-3 text-center">
          <div class="text-cyan-300 text-sm">CONFIDENCE</div>
          <div id="overallConfidenceDisplay">0%</div>
        </div>
        <div class="bg-gray-900 rounded-lg p-3 text-center">
          <div class="text-cyan-300 text-sm">Server Status</div>
          <div id="serverStatus" class="text-xl font-bold text-[#FFFFFF]">Connecting</div>
        </div>
      </div>
    </div>

    <div class="card shadow-lg">
      <h2 class="text-lg font-bold text-cyan-400 mb-2 font-orbitron">━━━━━━━━◆ History ◆━━━━━━━━</h2>
      <div id="historyContainer" class="space-y-2"></div>
      <button onclick="clearHistory()" class="ripple-button gradient-button mt-3 w-full text-white font-semibold rounded-lg">Clear All History</button>
    </div>
  </div>

  <div id="toastContainer" class="toast"></div>

  <script>
    // Configuration Constants
    const API_URL = "https://api.bdg88zf.com/api/webapi/GetNoaverageEmerdList";
    const API_RETRY_INTERVAL = 5000;
    const API_MAX_RETRIES = 3;
    const UPDATE_INTERVAL = 10000;
    const SMALL_NUMBERS = [0, 1, 2, 3, 4];
    const BIG_NUMBERS = [5, 6, 7, 8, 9];
    const MAX_HISTORY = 100;
    const TOAST_COOLDOWN = 1500;
    const PREDICTIONS_PER_REFRESH = 10;

    // DOM Elements Cache
    const DOM = {
      toastContainer: document.getElementById("toastContainer"),
      currentPeriodDisplay: document.getElementById("currentPeriodDisplay"),
      timerDisplay: document.getElementById("timerDisplay"),
      currentPredictionDisplay: document.getElementById("currentPredictionDisplay"),
      confidenceDisplay: document.getElementById("confidenceDisplay"),
      totalWins: document.getElementById("totalWins"),
      totalLosses: document.getElementById("totalLosses"),
      overallConfidenceDisplay: document.getElementById("overallConfidenceDisplay"),
      serverStatus: document.getElementById("serverStatus"),
      historyContainer: document.getElementById("historyContainer")
    };

    // State
    let historyData = [];
    let lastFetchedPeriod = null;
    let lastPrediction = null;
    let lastStatus = null;
    let globalPrediction = null;
    let streak = 0;
    let stats = { wins: 0, losses: 0 };
    let isFetching = false;
    let lastPeriodUpdate = null;
    let lastToastTime = 0;
    let predictionCount = 0;
    let currentLogicIndex = 0;
    let logicWeightCache = [];
    let logicPerformance = [
      { name: "WeightedSum", wins: 0, losses: 0 },
      { name: "StreakBased", wins: 0, losses: 0 },
      { name: "PatternBased", wins: 0, losses: 0 },
      { name: "NeuralNetInspired", wins: 0, losses: 0 },
      { name: "MarkovChain", wins: 0, losses: 0 },
      { name: "Bayesian", wins: 0, losses: 0 },
      { name: "ReinforcementLearning", wins: 0, losses: 0 },
      { name: "GradientBoosting", wins: 0, losses: 0 },
      { name: "FuzzyLogic", wins: 0, losses: 0 },
      { name: "DynamicTrend", wins: 0, losses: 0 }
    ];

    // Load State
    try {
      const storedHistory = localStorage.getItem('spyPredictorHistory');
      if (storedHistory) {
        historyData = JSON.parse(storedHistory);
        if (!Array.isArray(historyData)) {
          console.error("Invalid history data, resetting.");
          historyData = [];
        }
      }
      const storedStats = localStorage.getItem('spyPredictorStats');
      if (storedStats) stats = JSON.parse(storedStats);
      const storedLogic = localStorage.getItem('spyPredictorLogicPerformance');
      if (storedLogic) logicPerformance = JSON.parse(storedLogic) || logicPerformance;
    } catch (e) {
      console.error("Failed to load state:", e);
      showToast("Error loading saved data.", "error");
    }

    // Utility Functions
    const showToast = (message, type = "info", duration = 1500) => {
      const now = Date.now();
      if (now - lastToastTime < TOAST_COOLDOWN) return;
      lastToastTime = now;
      if (!DOM.toastContainer) {
        console.error("Toast container not found");
        return;
      }
      DOM.toastContainer.textContent = message;
      DOM.toastContainer.className = `toast show ${type}`;
      setTimeout(() => DOM.toastContainer.className = "toast", duration);
    };

    const saveHistory = () => {
      historyData = historyData.slice(0, MAX_HISTORY);
      try {
        localStorage.setItem('spyPredictorHistory', JSON.stringify(historyData));
        localStorage.setItem('spyPredictorStats', JSON.stringify(stats));
        localStorage.setItem('spyPredictorLogicPerformance', JSON.stringify(logicPerformance));
      } catch (e) {
        console.error("Error saving history:", e);
        showToast("Warning: History save failed.", "warning");
      }
    };

    const pad = (num) => num.toString().padStart(2, '0');

    const formatTimer = () => {
      const now = new Date();
      now.setTime(now.getTime() + (now.getTimezoneOffset() + 5.5 * 60) * 60 * 1000);
      const seconds = now.getSeconds();
      const remainingSeconds = 60 - seconds;
      return `${pad(0)} : ${pad(remainingSeconds)}`.replace(/(\d)(?=\d)/g, '$1 ');
    };

    const updateTimer = () => {
      if (DOM.timerDisplay) DOM.timerDisplay.innerText = formatTimer();
    };

    // AI Logics
    const analyzeRecentPatterns = (history) => {
      const recent = history.slice(0, 10).filter(h => h.result !== "-");
      let bigStreak = 0, smallStreak = 0;
      recent.forEach(h => {
        const num = Number(h.result);
        if (num >= 5) bigStreak++; else smallStreak++;
      });
      return { bigStreak, smallStreak, recentLength: recent.length };
    };

    const aiLogicWeightedSum = (history) => {
      const patterns = analyzeRecentPatterns(history);
      let score = 0, validCount = 0;
      history.forEach(h => {
        if (!h || h.result === "-") return;
        const isBig = Number(h.result) >= 5;
        score += isBig ? 1 : -1;
        validCount++;
      });
      score += patterns.bigStreak > patterns.smallStreak ? 0.5 : -0.5;
      return {
        size: score >= 0 ? "BIG" : "SMALL",
        confidence: Math.min(50, 30 + validCount * 2 + Math.abs(score) * 5),
        factor: `Weighted sum score: ${score}`
      };
    };

    const aiLogicStreakBased = (history) => {
      const patterns = analyzeRecentPatterns(history);
      const streakType = patterns.bigStreak > patterns.smallStreak ? "BIG" : "SMALL";
      return {
        size: patterns.bigStreak >= 3 ? "SMALL" : "BIG",
        confidence: Math.min(45, 30 + Math.max(patterns.bigStreakSink, patterns.smallStreak) * 5),
        factor: `Streak: ${streakType} (${patterns.bigStreak}/${patterns.smallStreak})`
      };
    };

    const aiLogicPatternBased = (history) => {
      const recent = history.slice(0, 10).filter(h => h.result !== "-").map(h => Number(h.result) >= 5 ? "BIG" : "SMALL");
      let score = 0, patternCount = 0;
      if (recent.length >= 2) {
        const currentPattern = recent.slice(0, 2).join('');
        for (let i = 2; i < recent.length - 1; i++) {
          if (recent.slice(i, i + 2).join('') === currentPattern) {
            patternCount++;
            if (recent[i - 1] === "BIG") score++;
            else score--;
          }
        }
      }
      return {
        size: score >= 0 ? "BIG" : "SMALL",
        confidence: Math.min(50, 30 + patternCount * 3),
        factor: `Pattern count: ${patternCount}`
      };
    };

    const aiLogicNeuralNetInspired = (history) => {
      let activation = 0, validCount = 0;
      const patterns = analyzeRecentPatterns(history);
      history.forEach(h => {
        if (!h || h.result === "-") return;
        activation += (Number(h.result) >= 5 ? 1 : -1) * 0.4;
        validCount++;
      });
      activation += (patterns.bigStreak - patterns.smallStreak) * 0.2;
      activation = 1 / (1 + Math.exp(-activation));
      return {
        size: activation >= 0.5 ? "BIG" : "SMALL",
        confidence: Math.min(50, 35 + validCount * 2),
        factor: `Neural activation: ${activation.toFixed(2)}`
      };
    };

    const aiLogicMarkovChain = (history) => {
      const recent = history.slice(0, 10).filter(h => h.result !== "-").map(h => Number(h.result) >= 5 ? "BIG" : "SMALL");
      const transitions = { BIG: { BIG: 0, SMALL: 0 }, SMALL: { BIG: 0, SMALL: 0 } };
      for (let i = 1; i < recent.length; i++) {
        transitions[recent[i - 1]][recent[i]]++;
      }
      const last = recent[0] || "BIG";
      const total = transitions[last].BIG + transitions[last].SMALL;
      const probBig = total > 0 ? transitions[last].BIG / total : 0.5;
      return {
        size: probBig >= 0.5 ? "BIG" : "SMALL",
        confidence: Math.min(50, 30 + total * 2),
        factor: `Markov prob BIG: ${probBig.toFixed(2)}`
      };
    };

    const aiLogicBayesian = (history) => {
      const recent = history.slice(0, 10).filter(h => h.result !== "-").map(h => Number(h.result) >= 5 ? "BIG" : "SMALL");
      const bigCount = recent.filter(r => r === "BIG").length;
      const totalCount = recent.length;
      const priorBig = 0.5;
      const likelihoodBig = totalCount > 0 ? bigCount / totalCount : 0.5;
      const posteriorBig = (likelihoodBig * priorBig) / ((likelihoodBig * priorBig) + ((1 - likelihoodBig) * (1 - priorBig)));
      return {
        size: posteriorBig >= 0.5 ? "BIG" : "SMALL",
        confidence: Math.min(50, 30 + totalCount * 2),
        factor: `Bayesian prob BIG: ${posteriorBig.toFixed(2)}`
      };
    };

    const aiLogicReinforcementLearning = (history) => {
      const qTable = { BIG: { reward: 0, count: 0 }, SMALL: { reward: 0, count: 0 } };
      history.forEach(h => {
        if (h.resultStatus !== "WIN" && h.resultStatus !== "LOSS") return;
        const action = h.sizePrediction;
        const reward = h.resultStatus === "WIN" ? 1 : -0.5;
        qTable[action].reward += reward;
        qTable[action].count++;
      });
      const bigQ = qTable.BIG.count > 0 ? qTable.BIG.reward / qTable.BIG.count : 0;
      const smallQ = qTable.SMALL.count > 0 ? qTable.SMALL.reward / qTable.SMALL.count : 0;
      return {
        size: bigQ >= smallQ ? "BIG" : "SMALL",
        confidence: Math.min(50, 35 + Math.abs(bigQ - smallQ) * 50),
        factor: `Q-values: BIG=${bigQ.toFixed(2)}, SMALL=${smallQ.toFixed(2)}`
      };
    };

    const aiLogicGradientBoosting = (history) => {
      let score = 0;
      const trees = [{ weight: 0.4, threshold: 0.5 }, { weight: 0.3, threshold: 0.3 }];
      const patterns = analyzeRecentPatterns(history);
      history.forEach(h => {
        if (!h || h.result === "-") return;
        const isBig = Number(h.result) >= 5;
        trees.forEach(t => score += t.weight * (isBig ? 1 : -1) * (h.confidence / 100 > t.threshold ? 1 : 0.5));
      });
      score += (patterns.bigStreak - patterns.smallStreak) * 0.3;
      return {
        size: score >= 0 ? "BIG" : "SMALL",
        confidence: Math.min(50, 35 + Math.abs(score) * 5),
        factor: `Gradient boost score: ${score.toFixed(2)}`
      };
    };

    const aiLogicFuzzyLogic = (history) => {
      let score = 0;
      const patterns = analyzeRecentPatterns(history);
      history.forEach(h => {
        if (!h || h.result === "-") return;
        const num = Number(h.result);
        const bigMembership = num >= 5 ? 1 : num / 5;
        const smallMembership = num < 5 ? 1 - num / 5 : 0;
        score += bigMembership - smallMembership;
      });
      score += (patterns.bigStreak - patterns.smallStreak) * 0.3;
      return {
        size: score >= 0 ? "BIG" : "SMALL",
        confidence: Math.min(50, 30 + Math.abs(score) * 5),
        factor: `Fuzzy score: ${score.toFixed(2)}`
      };
    };

    const aiLogicDynamicTrend = (history) => {
      const patterns = analyzeRecentPatterns(history);
      let