<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>JETHRO AI 2.0</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <div class="app">

    <header class="header">
      <div class="face-wrap" id="faceWrap">
        <div class="ring"></div>
        <img id="face" class="face" src="https://i.imgur.com/qZtBExZ.png" alt="Jethro">
        <div class="mouth"></div>
      </div>
      <h1 class="title">JETHRO AI</h1>
      <p class="subtitle">ARTIFICIAL INTELLIGENCE CORE</p>
      <div class="clock" id="clock">00:00:00</div>
      <div class="date" id="date">Loading…</div>
    </header>

    <section class="diagnostics">
      <div class="diag-head">
        <span>SYSTEM DIAGNOSTICS</span>
        <span class="live">LIVE</span>
      </div>
      <div class="diag-row"><span>Interface</span><span class="ok">OPERATIONAL</span></div>
      <div class="diag-row"><span>Chat System</span><span class="ok">READY</span></div>
      <div class="diag-row"><span>AI Connection</span><span class="ok" id="aiStatus">CHECKING</span></div>
      <div class="diag-row"><span>Voice Recognition</span><span class="bad" id="voiceStatus">CHECKING</span></div>
      <div class="diag-row"><span>Speech Output</span><span class="ok" id="speechStatus">CHECKING</span></div>
    </section>

    <section class="chat-card">
      <div class="chat-head">
        <h2>JETHRO CHAT</h2>
        <div class="head-btns">
          <button id="voiceBtn" class="reset" title="Toggle voice">🔊</button>
          <button id="resetBtn" class="reset">New chat</button>
        </div>
      </div>
      <p class="chat-sub">Your personal assistant</p>

      <div class="messages" id="messages"></div>

      <div class="input-row">
        <button id="micBtn" class="mic" title="Speak">🎤</button>
        <input id="input" type="text" placeholder="Type a message…" autocomplete="off">
        <button id="sendBtn" class="send">Send</button>
      </div>
    </section>

  </div>

  <script src="script.js"></script>
</body>
</html>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }

body {
  background: #060d1a;
  color: #dbe7f5;
  font-family: -apple-system, "Segoe UI", Roboto, sans-serif;
  min-height: 100vh;
  padding: 16px;
}

.app { max-width: 520px; margin: 0 auto; }

/* ---------- Header ---------- */
.header { text-align: center; padding: 10px 0 20px; }

.face-wrap {
  position: relative;
  width: 150px;
  height: 150px;
  margin: 0 auto 14px;
}

.ring {
  position: absolute;
  inset: 0;
  border: 2px solid rgba(0, 200, 255, 0.35);
  border-radius: 50%;
  animation: pulse 3s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% { transform: scale(1); opacity: 0.5; }
  50%      { transform: scale(1.06); opacity: 1; }
}

.face {
  position: absolute;
  inset: 10px;
  width: calc(100% - 20px);
  height: calc(100% - 20px);
  border-radius: 50%;
  object-fit: cover;
  transition: transform 0.15s ease;
}

.face.nod   { animation: nod 0.6s ease; }
.face.blink { animation: blink 0.2s ease; }

@keyframes nod {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(8px); }
}

@keyframes blink {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.55; }
}

.mouth {
  position: absolute;
  left: 50%;
  top: 68%;
  width: 34px;
  height: 8px;
  margin-left: -17px;
  background: #1a0f0f;
  border-radius: 50%;
  opacity: 0;
  transition: height 0.1s ease, opacity 0.1s ease;
  pointer-events: none;
}

.face-wrap.speaking .mouth {
  opacity: 0.85;
  animation: talk 0.28s ease-in-out infinite alternate;
}

@keyframes talk {
  from { height: 6px;  }
  to   { height: 20px; }
}

.title {
  font-size: 26px;
  letter-spacing: 8px;
  color: #4fd8ff;
  font-weight: 600;
}

.subtitle {
  font-size: 10px;
  letter-spacing: 4px;
  color: #5c7691;
  margin-top: 6px;
}

.clock {
  font-size: 38px;
  font-weight: 300;
  letter-spacing: 2px;
  margin-top: 14px;
}

.date { font-size: 13px; color: #5c7691; margin-top: 4px; }

/* ---------- Diagnostics ---------- */
.diagnostics {
  background: rgba(12, 24, 42, 0.9);
  border: 1px solid rgba(0, 180, 255, 0.15);
  border-radius: 14px;
  padding: 16px;
  margin-bottom: 16px;
}

.diag-head {
  display: flex;
  justify-content: space-between;
  font-size: 11px;
  letter-spacing: 2px;
  color: #5c7691;
  margin-bottom: 12px;
}

.live { color: #37e0a0; }

.diag-row {
  display: flex;
  justify-content: space-between;
  font-size: 14px;
  padding: 7px 0;
  color: #a9c0d6;
}

.ok  { color: #37e0a0; font-size: 12px; letter-spacing: 1px; }
.bad { color: #ff5c72; font-size: 12px; letter-spacing: 1px; }

/* ---------- Chat ---------- */
.chat-card {
  background: rgba(12, 24, 42, 0.9);
  border: 1px solid rgba(0, 180, 255, 0.15);
  border-radius: 14px;
  padding: 16px;
}

.chat-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.chat-head h2 {
  font-size: 15px;
  letter-spacing: 3px;
  color: #4fd8ff;
  font-weight: 600;
}

.head-btns { display: flex; gap: 6px; }

.reset {
  background: transparent;
  border: 1px solid rgba(0, 180, 255, 0.3);
  color: #7fa8c9;
  font-size: 11px;
  padding: 5px 10px;
  border-radius: 20px;
  cursor: pointer;
}

.chat-sub { font-size: 11px; color: #5c7691; margin: 4px 0 14px; }

.messages {
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-height: 380px;
  overflow-y: auto;
  padding-right: 4px;
}

.msg {
  padding: 12px 14px;
  border-radius: 12px;
  font-size: 14px;
  line-height: 1.55;
  max-width: 88%;
  white-space: pre-wrap;
}

.msg.jethro {
  align-self: flex-start;
  background: rgba(0, 140, 200, 0.12);
  border-left: 3px solid #4fd8ff;
}

.msg.you {
  align-self: flex-end;
  background: rgba(120, 80, 220, 0.16);
  border-left: 3px solid #9b7bff;
}

.msg .who {
  display: block;
  font-size: 10px;
  letter-spacing: 2px;
  color: #5c7691;
  margin-bottom: 6px;
}

/* ---------- Input ---------- */
.input-row {
  display: flex;
  gap: 8px;
  margin-top: 16px;
}

.input-row input {
  flex: 1;
  background: rgba(6, 16, 30, 0.9);
  border: 1px solid rgba(0, 180, 255, 0.2);
  border-radius: 10px;
  padding: 12px;
  color: #dbe7f5;
  font-size: 14px;
  outline: none;
}

.input-row input:focus { border-color: #4fd8ff; }

.mic, .send {
  border: none;
  border-radius: 10px;
  padding: 0 16px;
  font-size: 14px;
  cursor: pointer;
}

.mic { background: rgba(0, 180, 255, 0.15); color: #4fd8ff; }
.mic.listening { background: #ff5c72; color: #fff; }

.send { background: #4fd8ff; color: #04121f; font-weight: 600; }
</style>
<script>
/* =========================================================
   JETHRO AI 2.0 — script.js  (fixed)
   ========================================================= */

console.log("1. script started");

const WORKER_URL = "https://jethroai2.abayomimondayvictor.workers.dev";

const $ = (id) => {
  const el = document.getElementById(id);
  if (!el) console.warn("MISSING ELEMENT:", id);
  return el;
};

const messagesEl = $("messages");
const inputEl    = $("input");
const sendBtn    = $("sendBtn");
const micBtn     = $("micBtn");
const resetBtn   = $("resetBtn");
const voiceBtn   = $("voiceBtn");
const faceEl     = $("face");
const faceWrap   = $("faceWrap");
const voiceEl    = $("voiceStatus");
const speechEl   = $("speechStatus");
const aiEl       = $("aiStatus");

console.log("2. elements found");

window.onerror = function (msg, src, line) {
  console.error("SCRIPT ERROR at line " + line + ": " + msg);
};

/* ---------- Memory ---------- */
let history = [];
try {
  const saved = JSON.parse(localStorage.getItem("jethroHistory") || "[]");
  if (Array.isArray(saved)) {
    // drop any broken entries left over from earlier bugs
    history = saved.filter(
      (m) =>
        m &&
        typeof m.content === "string" &&
        m.content.trim() !== "" &&
        m.content !== "No reply." &&
        (m.role === "user" || m.role === "assistant")
    );
  }
} catch (e) {
  console.warn("localStorage blocked:", e.message);
  history = [];
}

function saveHistory() {
  try {
    localStorage.setItem("jethroHistory", JSON.stringify(history));
  } catch (e) {}
}

/* ---------- Bubbles ---------- */
function addBubble(text, who, scroll = true) {
  if (!messagesEl) return;
  const div = document.createElement("div");
  div.className = "msg " + who;

  const label = document.createElement("span");
  label.className = "who";
  label.textContent = who === "you" ? "YOU" : "JETHRO AI";

  div.appendChild(label);
  div.appendChild(document.createTextNode(text));
  messagesEl.appendChild(div);

  if (scroll) messagesEl.scrollTop = messagesEl.scrollHeight;
}

function renderHistory() {
  if (!messagesEl) return;
  messagesEl.innerHTML = "";
  history.forEach((m) => {
    addBubble(m.content, m.role === "user" ? "you" : "jethro", false);
  });
  messagesEl.scrollTop = messagesEl.scrollHeight;
}

/* ---------- Face ---------- */
function playFace(state, duration = 600) {
  if (!faceEl) return;
  faceEl.classList.add(state);
  setTimeout(() => faceEl.classList.remove(state), duration);
}

setInterval(() => playFace("blink", 200), 4500);

/* ---------- Clock ---------- */
function tick() {
  const now = new Date();
  const clockEl = document.getElementById("clock");
  const dateEl = document.getElementById("date");

  if (clockEl) clockEl.textContent = now.toLocaleTimeString("en-GB");
  if (dateEl) {
    dateEl.textContent = now.toLocaleDateString("en-GB", {
      weekday: "long",
      day: "numeric",
      month: "long",
      year: "numeric",
    });
  }
}
tick();
setInterval(tick, 1000);

console.log("3. clock running");

/* ---------- Speech output ---------- */
let voiceOn = true;
let chosenVoice = null;

try {
  if (window.speechSynthesis) {
    const loadVoices = () => {
      const voices = window.speechSynthesis.getVoices() || [];
      chosenVoice =
        voices.find((v) => /en-NG/i.test(v.lang) && /male/i.test(v.name)) ||
        voices.find((v) => /en-GB/i.test(v.lang) && /male/i.test(v.name)) ||
        voices.find((v) => /^en/i.test(v.lang)) ||
        null;
    };

    loadVoices();
    window.speechSynthesis.onvoiceschanged = loadVoices;

    if (speechEl) {
      speechEl.textContent = "READY";
      speechEl.className = "ok";
    }
  } else if (speechEl) {
    speechEl.textContent = "UNSUPPORTED";
    speechEl.className = "bad";
  }
} catch (e) {
  console.error("speech init failed:", e.message);
}

function speak(text, force = false) {
  try {
    if (!window.speechSynthesis) return;
    if (!voiceOn && !force) return;

    window.speechSynthesis.cancel();

    const u = new SpeechSynthesisUtterance(text);
    u.lang = "en-NG";
    u.rate = 1;
    u.pitch = 0.95;
    if (chosenVoice) u.voice = chosenVoice;

    u.onstart = () => {
      if (faceWrap) faceWrap.classList.add("speaking");
    };

    u.onend = () => {
      if (faceWrap) faceWrap.classList.remove("speaking");
      playFace("nod", 600);
    };

    u.onerror = () => {
      if (faceWrap) faceWrap.classList.remove("speaking");
    };

    window.speechSynthesis.speak(u);
  } catch (e) {
    console.error("speak failed:", e.message);
  }
}

if (voiceBtn) {
  voiceBtn.addEventListener("click", () => {
    voiceOn = !voiceOn;
    voiceBtn.textContent = voiceOn ? "🔊" : "🔇";
    if (!voiceOn) {
      try {
        window.speechSynthesis.cancel();
      } catch (e) {}
      if (faceWrap) faceWrap.classList.remove("speaking");
    }
  });
}

console.log("4. speech ready");

/* ---------- Send message ---------- */
async function sendMessage(text) {
  text = (text || "").trim();
  if (!text) return;

  addBubble(text, "you");

  // build the payload from a CLEAN copy, then commit to history
  const outgoing = history
    .filter((m) => m && m.content && m.content.trim() !== "" && m.content !== "No reply.")
    .concat([{ role: "user", content: text }]);

  if (inputEl) inputEl.value = "";
  playFace("mouth-open", 900);

  const wantsSpeech = /^(say|speak|read|tell me|repeat|pronounce)\b/i.test(text);

  if (aiEl) {
    aiEl.textContent = "THINKING";
    aiEl.className = "ok";
  }

  try {
    const res = await fetch(WORKER_URL, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ messages: outgoing }),
    });

    const raw = await res.text();
    console.log("WORKER STATUS:", res.status);
    console.log("WORKER BODY:", raw);

    let data;
    try {
      data = JSON.parse(raw);
    } catch (e) {
      addBubble("Bad response from Worker: " + raw.slice(0, 200), "jethro");
      if (aiEl) { aiEl.textContent = "ERROR"; aiEl.className = "bad"; }
      return;
    }

    let reply = data && data.reply ? String(data.reply).trim() : "";

    // if the Worker handed back an error string, show it plainly
    if (!reply || reply === "No reply.") {
      reply = "No reply. Worker said: " + raw.slice(0, 200);
    }

    addBubble(reply, "jethro");

    // only store real exchanges in memory
    if (!reply.startsWith("No reply.") && !reply.startsWith("Bad response")) {
      history.push({ role: "user", content: text });
      history.push({ role: "assistant", content: reply });
      saveHistory();
    }

    if (aiEl) { aiEl.textContent = "CONNECTED"; aiEl.className = "ok"; }

    speak(reply, wantsSpeech);

  } catch (err) {
    console.error("send failed:", err.message);
    addBubble("Connection error: " + err.message, "jethro");
    if (aiEl) { aiEl.textContent = "OFFLINE"; aiEl.className = "bad"; }
  }
}

if (sendBtn) {
  sendBtn.addEventListener("click", () => sendMessage(inputEl ? inputEl.value : ""));
}

if (inputEl) {
  inputEl.addEventListener("keydown", (e) => {
    if (e.key === "Enter") {
      e.preventDefault();
      sendMessage(inputEl.value);
    }
  });
}

/* ---------- Reset ---------- */
if (resetBtn) {
  resetBtn.addEventListener("click", () => {
    history = [];
    saveHistory();
    if (messagesEl) messagesEl.innerHTML = "";
    addBubble("Memory cleared. Starting fresh.", "jethro");
  });
}

console.log("5. send wired");

/* ---------- Voice recognition ---------- */
try {
  const SR = window.SpeechRecognition || window.webkitSpeechRecognition;

  if (!SR) {
    if (voiceEl) { voiceEl.textContent = "UNSUPPORTED"; voiceEl.className = "bad"; }
  } else {
    const rec = new SR();
    rec.lang = "en-NG";
    rec.interimResults = false;
    rec.continuous = false;

    rec.onstart = () => {
      if (micBtn) micBtn.classList.add("listening");
      if (voiceEl) { voiceEl.textContent = "LISTENING"; voiceEl.className = "ok"; }
    };

    rec.onend = () => {
      if (micBtn) micBtn.classList.remove("listening");
      if (voiceEl) { voiceEl.textContent = "READY"; voiceEl.className = "ok"; }
    };

    rec.onresult = (e) => {
      const said = e.results[0][0].transcript;
      sendMessage(said);
    };

    rec.onerror = (e) => {
      if (micBtn) micBtn.classList.remove("listening");
      if (voiceEl) {
        voiceEl.textContent = String(e.error).toUpperCase();
        voiceEl.className = "bad";
      }
      console.error("VOICE ERROR:", e.error);
    };

    if (micBtn) {
      micBtn.addEventListener("click", () => {
        try {
          rec.start();
        } catch (err) {
          console.error("start failed:", err.message);
        }
      });
    }

    if (voiceEl) { voiceEl.textContent = "READY"; voiceEl.className = "ok"; }
  }
} catch (e) {
  console.error("voice init failed:", e.message);
}

console.log("6. voice ready");

/* ---------- Boot ---------- */
renderHistory();
if (history.length === 0) {
  addBubble("Hello. I'm Jethro AI. How can I help you today?", "jethro");
}

console.log("7. JETHRO READY");
</script>