import { useState, useRef, useEffect, useCallback } from "react";

// ─── helpers ──────────────────────────────────────────────────────────────────

function formatTimestamp(date) {
  return date.toISOString().replace("T", " ").replace("Z", "");
}

function saveLogsToFile(lines, sessionLabel) {
  const text = lines.map((l) => `[${l.ts}] ${l.text}`).join("\n");
  const blob = new Blob([text], { type: "text/plain" });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = `serial-log-${sessionLabel}.txt`;
  a.click();
  URL.revokeObjectURL(url);
}

function persistSession(lines) {
  const saved = JSON.parse(localStorage.getItem("bellsystems_serial_logs") || "[]");
  const label = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
  const session = {
    id: Date.now(),
    label,
    savedAt: new Date().toISOString(),
    lineCount: lines.length,
    lines,
  };
  saved.unshift(session);
  // Keep last 20 sessions
  localStorage.setItem("bellsystems_serial_logs", JSON.stringify(saved.slice(0, 20)));
  return label;
}

// ─── sub-components ───────────────────────────────────────────────────────────

function InfoBox({ type = "info", children }) {
  const styles = {
    info:    { bg: "var(--badge-blue-bg)",  border: "#1e3a5f",  color: "var(--badge-blue-text)" },
    warning: { bg: "#2e1a00",               border: "#7c4a00",  color: "#fb923c" },
    error:   { bg: "var(--danger-bg)",      border: "var(--danger)", color: "var(--danger-text)" },
    success: { bg: "var(--success-bg)",     border: "var(--success)", color: "var(--success-text)" },
  };
  const s = styles[type] || styles.info;
  return (
    <div
      className="text-sm rounded-md p-3 border"
      style={{ backgroundColor: s.bg, borderColor: s.border, color: s.color }}
    >
      {children}
    </div>
  );
}

// ─── Main Page ────────────────────────────────────────────────────────────────

export default function SerialMonitorPage() {
  const [connected, setConnected]   = useState(false);
  const [connecting, setConnecting] = useState(false);
  const [portName, setPortName]     = useState("");
  const [lines, setLines]           = useState([]);
  const [error, setError]           = useState("");
  const [saved, setSaved]           = useState(false);
  const [savedLabel, setSavedLabel] = useState("");

  const portRef       = useRef(null);
  const readerRef     = useRef(null);
  const readingRef    = useRef(false);
  const logEndRef     = useRef(null);
  const linesRef      = useRef([]);  // mirror for use inside async loop

  const webSerialAvailable = "serial" in navigator;

  // Keep linesRef in sync
  useEffect(() => {
    linesRef.current = lines;
  }, [lines]);

  // Auto-scroll
  useEffect(() => {
    logEndRef.current?.scrollIntoView({ behavior: "smooth" });
  }, [lines]);

  const appendLine = useCallback((text) => {
    const entry = { ts: formatTimestamp(new Date()), text };
    setLines((prev) => [...prev, entry]);
  }, []);

  const startReading = useCallback(async (port) => {
    const decoder = new TextDecoderStream();
    port.readable.pipeTo(decoder.writable).catch(() => {});
    const reader = decoder.readable.getReader();
    readerRef.current = reader;
    readingRef.current = true;

    let buffer = "";
    try {
      while (readingRef.current) {
        const { value, done } = await reader.read();
        if (done) break;
        buffer += value;
        const parts = buffer.split("\n");
        buffer = parts.pop(); // keep incomplete line
        for (const part of parts) {
          const trimmed = part.replace(/\r$/, "");
          if (trimmed) appendLine(trimmed);
        }
      }
    } catch (err) {
      if (readingRef.current) {
        setError("Serial connection lost: " + (err.message || String(err)));
        setConnected(false);
      }
    }
  }, [appendLine]);

  const handleConnect = async () => {
    setError("");
    setSaved(false);
    setConnecting(true);
    try {
      const port = await navigator.serial.requestPort();
      await port.open({ baudRate: 115200 });

      const info = port.getInfo?.() || {};
      const label = info.usbVendorId
        ? `USB ${info.usbVendorId.toString(16).toUpperCase()}:${(info.usbProductId || 0).toString(16).toUpperCase()}`
        : "Serial Port";

      portRef.current = port;
      setPortName(label);
      setConnected(true);
      setLines([]);
      appendLine("--- Serial monitor connected ---");
      startReading(port);
    } catch (err) {
      if (err.name !== "NotFoundError") {
        setError(err.message || "Failed to open port.");
      }
    } finally {
      setConnecting(false);
    }
  };

  const handleDisconnect = async () => {
    readingRef.current = false;
    try { readerRef.current?.cancel(); } catch (_) {}
    try { await portRef.current?.close(); } catch (_) {}
    portRef.current = null;
    readerRef.current = null;
    setConnected(false);
    appendLine("--- Disconnected ---");
  };

  const handleSave = () => {
    if (lines.length === 0) return;
    const label = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
    // Save to localStorage for the Log Viewer page
    persistSession(lines);
    // Also download as a .txt file
    saveLogsToFile(lines, label);
    setSaved(true);
    setSavedLabel(label);
  };

  const handleClear = () => {
    setLines([]);
    setSaved(false);
  };

  return (
    <div
      className="min-h-screen flex flex-col"
      style={{ backgroundColor: "var(--bg-primary)", color: "var(--text-primary)" }}
    >
      {/* ── Top bar ── */}
      <div
        className="flex items-center justify-between px-6 py-4 border-b"
        style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)" }}
      >
        <div className="flex items-center gap-3">
          <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" style={{ color: "var(--accent)" }}>
            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.8}
              d="M9 3H5a2 2 0 00-2 2v4m6-6h10a2 2 0 012 2v4M9 3v18m0 0h10a2 2 0 002-2V9M9 21H5a2 2 0 01-2-2V9m0 0h18" />
          </svg>
          <span className="font-bold text-base" style={{ color: "var(--text-heading)" }}>
            BellSystems — Serial Monitor
          </span>
        </div>

        <div className="flex items-center gap-2">
          {/* Connection indicator */}
          <span
            className="inline-block w-2 h-2 rounded-full"
            style={{ backgroundColor: connected ? "#22c55e" : "var(--border-primary)" }}
          />
          <span className="text-sm" style={{ color: connected ? "var(--text-heading)" : "var(--text-muted)" }}>
            {connected ? portName || "Connected" : "Not connected"}
          </span>
        </div>
      </div>

      {/* ── Body ── */}
      <div className="flex-1 flex flex-col max-w-4xl w-full mx-auto px-6 py-6 gap-4">

        {/* Browser support warning */}
        {!webSerialAvailable && (
          <InfoBox type="warning">
            <strong>Browser not supported.</strong> Serial Monitor requires Google Chrome or Microsoft Edge on a desktop.
            Safari, Firefox, and mobile browsers are not supported.
          </InfoBox>
        )}

        {/* Error */}
        {error && <InfoBox type="error">{error}</InfoBox>}

        {/* Success feedback */}
        {saved && (
          <InfoBox type="success">
            Logs saved! Downloaded as <strong>serial-log-{savedLabel}.txt</strong> and stored in Log Viewer.
          </InfoBox>
        )}

        {/* Controls */}
        <div
          className="rounded-lg border p-4 flex flex-wrap items-center justify-between gap-3"
          style={{ backgroundColor: "var(--bg-card)", borderColor: connected ? "var(--accent)" : "var(--border-primary)" }}
        >
          <div className="flex items-center gap-3">
            {!connected ? (
              <button
                onClick={handleConnect}
                disabled={!webSerialAvailable || connecting}
                className="px-5 py-2 rounded-md text-sm font-semibold cursor-pointer disabled:opacity-40 disabled:cursor-not-allowed hover:opacity-90 transition-opacity"
                style={{ backgroundColor: "var(--btn-primary)", color: "var(--text-white)" }}
              >
                {connecting ? "Waiting…" : "Connect to Port"}
              </button>
            ) : (
              <button
                onClick={handleDisconnect}
                className="px-5 py-2 rounded-md text-sm font-medium cursor-pointer hover:opacity-80 transition-opacity"
                style={{ backgroundColor: "var(--bg-card-hover)", color: "var(--text-secondary)", border: "1px solid var(--border-primary)" }}
              >
                Disconnect
              </button>
            )}

            <span className="text-xs" style={{ color: "var(--text-muted)" }}>
              {lines.length > 0 ? `${lines.length} lines` : "No output yet"}
            </span>
          </div>

          <div className="flex items-center gap-2">
            <button
              onClick={handleClear}
              disabled={lines.length === 0}
              className="px-4 py-2 rounded-md text-sm font-medium cursor-pointer disabled:opacity-40 disabled:cursor-not-allowed hover:opacity-80 transition-opacity"
              style={{ backgroundColor: "var(--bg-card-hover)", color: "var(--text-muted)", border: "1px solid var(--border-primary)" }}
            >
              Clear
            </button>
            <button
              onClick={handleSave}
              disabled={lines.length === 0}
              className="px-5 py-2 rounded-md text-sm font-semibold cursor-pointer disabled:opacity-40 disabled:cursor-not-allowed hover:opacity-90 transition-opacity flex items-center gap-2"
              style={{ backgroundColor: "var(--accent)", color: "var(--bg-primary)" }}
            >
              <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2}
                  d="M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4" />
              </svg>
              Save Logs
            </button>
          </div>
        </div>

        {/* How-to hint when not connected */}
        {!connected && lines.length === 0 && (
          <div
            className="rounded-lg border p-4 space-y-2"
            style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-secondary)" }}
          >
            <p className="text-xs font-semibold uppercase tracking-wide" style={{ color: "var(--text-muted)" }}>
              How to use
            </p>
            {[
              "Connect your BellSystems device via USB cable.",
              "Click \"Connect to Port\" — a browser popup will appear.",
              "Select the COM port for your device (look for CP210x, CH340, or USB Serial).",
              "Serial output will appear live at 115200 baud.",
              "When finished, click \"Save Logs\" to download a .txt file and store it in Log Viewer.",
            ].map((step, i) => (
              <div key={i} className="flex items-start gap-2">
                <span className="text-xs font-bold flex-shrink-0 mt-0.5" style={{ color: "var(--accent)" }}>{i + 1}.</span>
                <span className="text-xs" style={{ color: "var(--text-muted)" }}>{step}</span>
              </div>
            ))}
          </div>
        )}

        {/* Log output */}
        <div
          className="rounded-md border overflow-y-auto font-mono text-xs flex-1"
          style={{
            backgroundColor: "#070d07",
            borderColor: "var(--border-secondary)",
            color: "#7ec87e",
            minHeight: 400,
            maxHeight: "calc(100vh - 340px)",
            padding: "12px 14px",
          }}
        >
          {lines.length === 0 ? (
            <span style={{ color: "#3a5c3a" }}>Waiting for serial output…</span>
          ) : (
            lines.map((l, i) => (
              <div key={i} className="leading-relaxed">
                <span style={{ color: "#3a6b3a", userSelect: "none" }}>{l.ts} </span>
                <span>{l.text}</span>
              </div>
            ))
          )}
          <div ref={logEndRef} />
        </div>
      </div>

      {/* ── Footer ── */}
      <div
        className="border-t px-6 py-3 text-center"
        style={{ borderColor: "var(--border-primary)", backgroundColor: "var(--bg-card)" }}
      >
        <span className="text-xs" style={{ color: "var(--text-muted)" }}>
          BellSystems Serial Monitor · 115200 baud · Chrome / Edge only
        </span>
      </div>
    </div>
  );
}
