import React, { useEffect, useState, useRef, useCallback } from "react";
import { useStore } from "../state/store";
import { useNavigate } from "react-router-dom";
import "./Orbit.css";

const API_BASE = process.env.REACT_APP_API_BASE || "";

export function Orbit() {
  const { setUi } = useStore();
  const navigate = useNavigate();
  const [isActive, setIsActive] = useState(false);
  const [position, setPosition] = useState({ x: 100, y: 100 });
  const [size, setSize] = useState(30);

  const synthRef = useRef(window.speechSynthesis);
  const recognitionRef = useRef(null);
  const sleepTimeoutRef = useRef(null);
  const draggingRef = useRef(false);
  const resizingRef = useRef(false);
  const offsetRef = useRef({ x: 0, y: 0 });
  const audioRef = useRef(null);

  // Gesture refs
  const lastTapRef = useRef(0);
  const longPressTimerRef = useRef(null);
  const isLongPressRef = useRef(false);
  const disableSleepRef = useRef(false);

  // 🎨 Orb visual state
  const setOrbStyle = useCallback((state) => {
    const root = document.documentElement;
    const styles = {
      dormant: {
        "--orb-core": "rgba(100,100,255,0.3)",
        "--orb-glow": "rgba(80,80,220,0.2)",
        "--orb-ray": "transparent",
        "--orb-scale": "0.8",
        "--orb-opacity": "0.4",
      },
      wake: {
        "--orb-core": "rgba(120,120,255,0.8)",
        "--orb-glow": "rgba(100,100,255,0.5)",
        "--orb-ray": "transparent",
        "--orb-scale": "1",
        "--orb-opacity": "1",
      },
      listening: {
        "--orb-core": "rgba(0,230,255,0.9)",
        "--orb-glow": "rgba(0,200,255,0.6)",
        "--orb-ray": "transparent",
        "--orb-scale": "1.1",
        "--orb-opacity": "1",
      },
      thinking: {
        "--orb-core": "rgba(255,180,0,0.8)",
        "--orb-glow": "rgba(255,160,0,0.5)",
        "--orb-ray": "transparent",
        "--orb-scale": "1.05",
        "--orb-opacity": "1",
      },
      speaking: {
        "--orb-core": "rgba(255,241,118,0.9)",
        "--orb-glow": "rgba(255,225,100,0.5)",
        "--orb-ray": "rgba(255,241,118,0.3)",
        "--orb-scale": "1",
        "--orb-opacity": "1",
      },
      error: {
        "--orb-core": "rgba(255,80,80,0.8)",
        "--orb-glow": "rgba(220,60,60,0.5)",
        "--orb-ray": "transparent",
        "--orb-scale": "1",
        "--orb-opacity": "1",
      },
      warning: {
        "--orb-core": "rgba(255,165,0,0.8)",
        "--orb-glow": "rgba(255,140,0,0.5)",
        "--orb-ray": "transparent",
        "--orb-scale": "1",
        "--orb-opacity": "1",
      },
    };
    const selected = styles[state] || styles["dormant"];
    Object.keys(selected).forEach((key) => root.style.setProperty(key, selected[key]));
  }, []);

  // 📴 Stop & sleep
  const stopAll = useCallback(() => {
    if (synthRef.current.speaking) synthRef.current.cancel();
    if (recognitionRef.current) {
      try { recognitionRef.current.stop(); } catch {}
    }
    setUi((u) => ({ ...u, orbit: "dormant" }));
    setOrbStyle("dormant");
    setIsActive(false);
    if (sleepTimeoutRef.current) clearTimeout(sleepTimeoutRef.current);
  }, [setUi, setOrbStyle]);

  // 🗣 Speak
  const speak = useCallback((text, after) => {
    if (!text) return;
    setOrbStyle("speaking");
    setUi((u) => ({ ...u, orbit: "speaking" }));

    const utter = new SpeechSynthesisUtterance(text);
    utter.onend = () => {
      if (isActive) {
        setOrbStyle("listening");
        setUi((u) => ({ ...u, orbit: "listening" }));
        if (!disableSleepRef.current) resetSleepTimer();
      } else {
        setOrbStyle("dormant");
      }
      if (after) after();
    };
    utter.onerror = () => setOrbStyle("error");
    synthRef.current.speak(utter);
  }, [isActive, setUi, setOrbStyle]);

  // ⏲ Sleep timer
  const resetSleepTimer = useCallback(() => {
    if (disableSleepRef.current) return;
    if (sleepTimeoutRef.current) clearTimeout(sleepTimeoutRef.current);
    sleepTimeoutRef.current = setTimeout(() => {
      speak("Going to sleep", stopAll);
    }, 15000);
  }, [speak, stopAll]);

  // 💬 Send text to backend chat
  const queryBackend = async (message) => {
    try {
      setOrbStyle("thinking");
      setUi((u) => ({ ...u, orbit: "thinking" }));

      const token = localStorage.getItem("token");
      const formData = new FormData();
      formData.append("text", message);

      const res = await fetch(`${API_BASE}/v1/chat`, {
        method: "POST",
        headers: { Authorization: `Bearer ${token}` },
        body: formData,
      });
      const data = await res.json();
      const reply = data.reply || "I don’t have an answer right now.";
      speak(reply);
    } catch (err) {
      console.error("Backend error:", err);
      speak("Sorry, I couldn’t reach the knowledge base.");
      setOrbStyle("warning");
      setUi((u) => ({ ...u, orbit: "warning" }));
    }
  };

  // 🎙 Speech Recognition
  useEffect(() => {
    const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
    if (!SR) return console.warn("SpeechRecognition not supported");

    recognitionRef.current = new SR();
    recognitionRef.current.continuous = true;
    recognitionRef.current.interimResults = false;
    recognitionRef.current.lang = "en-US";

    recognitionRef.current.onresult = (e) => {
      const transcript = e.results[e.results.length - 1][0].transcript.trim();
      console.log("Heard:", transcript);

      if (!isActive) return;
      if (transcript.toLowerCase().includes("go to sleep")) {
        speak("Going to sleep", stopAll);
        return;
      }
      queryBackend(transcript);
    };

    recognitionRef.current.onend = () => recognitionRef.current.start();
    recognitionRef.current.start();

    return () => recognitionRef.current && recognitionRef.current.stop();
  }, [isActive, stopAll, speak]);

  // 👆 Tap/longpress handlers
  const handlePointerDown = () => {
    const now = Date.now();
    if (now - lastTapRef.current < 300) {
      // Double tap → go to chat
      navigate("/chat");
    }
    lastTapRef.current = now;

    longPressTimerRef.current = setTimeout(() => {
      isLongPressRef.current = true;
      disableSleepRef.current = true;
      setIsActive(true);
      setOrbStyle("wake");
      setUi((u) => ({ ...u, orbit: "listening" }));
      if (audioRef.current) audioRef.current.play().catch(() => {});
      speak("Long press mode active. I'm listening continuously.");
    }, 600);
  };

  const handlePointerUp = () => {
    if (longPressTimerRef.current) clearTimeout(longPressTimerRef.current);
    if (isLongPressRef.current) {
      isLongPressRef.current = false;
      disableSleepRef.current = false;
      resetSleepTimer();
      speak("Long press released. Sleep timer re-enabled.");
    }
  };

  // 🖱 Drag + resize
  const handleMouseDown = (e, mode) => {
    if (mode === "drag") draggingRef.current = true;
    if (mode === "resize") resizingRef.current = true;
    offsetRef.current = { x: e.clientX, y: e.clientY };
  };

  const handleMouseMove = (e) => {
    if (draggingRef.current) {
      setPosition((pos) => {
        const newPos = { x: pos.x + (e.clientX - offsetRef.current.x), y: pos.y + (e.clientY - offsetRef.current.y) };
        offsetRef.current = { x: e.clientX, y: e.clientY };
        return newPos;
      });
    }
    if (resizingRef.current) {
      setSize((s) => Math.max(80, s + (e.clientX - offsetRef.current.x)));
      offsetRef.current = { x: e.clientX, y: e.clientY };
    }
  };

  const handleMouseUp = () => {
    draggingRef.current = false;
    resizingRef.current = false;
  };

  useEffect(() => {
    window.addEventListener("mousemove", handleMouseMove);
    window.addEventListener("mouseup", handleMouseUp);
    return () => {
      window.removeEventListener("mousemove", handleMouseMove);
      window.removeEventListener("mouseup", handleMouseUp);
    };
  }, []);

  // 💾 Save/load state
  useEffect(() => {
    const saved = JSON.parse(localStorage.getItem("orbit_state") || "{}");
    if (saved.x && saved.y) setPosition({ x: saved.x, y: saved.y });
    if (saved.size) setSize(saved.size);
  }, []);
  useEffect(() => {
    localStorage.setItem("orbit_state", JSON.stringify({ ...position, size }));
  }, [position, size]);

  return (
    <div
      className="orbit-wrapper"
      style={{ left: position.x, top: position.y, width: size, height: size }}
    >
      <audio ref={audioRef} src="/orbit.wav" preload="auto" />
      <div
        className="orbit"
        onMouseDown={(e) => handleMouseDown(e, "drag")}
        onPointerDown={handlePointerDown}
        onPointerUp={handlePointerUp}
        title="Orbit Assistant"
      />
      <div
        className="orbit-resize-handle"
        onMouseDown={(e) => handleMouseDown(e, "resize")}
      />
    </div>
  );
}
