import { useEffect, useState, useCallback, useRef } from "react";
import { API_BASE } from "./config";

export function Playbook() {
  const [playbooks, setPlaybooks] = useState([]);
  const [selectedId, setSelectedId] = useState(null);
  const [form, setForm] = useState({ title: "", goal: "", instructions: "", tags: "" });
  const [search, setSearch] = useState("");
  const [message, setMessage] = useState("");
  const dragItem = useRef(null);
  const dragOverItem = useRef(null);

  const normalizePlaybooks = (data) => {
    if (!data) return [];
    if (Array.isArray(data)) return data;
    if (Array.isArray(data.playbooks)) return data.playbooks;
    if (typeof data === "object") return Object.values(data);
    return [];
  };

  const loadPlaybooks = useCallback(async () => {
    try {
      const res = await fetch(`${API_BASE}/playbooks`);
      if (!res.ok) { setPlaybooks([]); return; }
      const data = await res.json().catch(() => null);
      setPlaybooks(normalizePlaybooks(data));
    } catch {
      setPlaybooks([]);
    }
  }, []);

  useEffect(() => { loadPlaybooks(); }, [loadPlaybooks]);

  const safeString = (v) => (v == null ? "" : String(v));

  const filteredPlaybooks = Array.isArray(playbooks)
    ? playbooks.filter(p => {
        if (!search.trim()) return true;
        const q = search.toLowerCase();
        return (
          safeString(p.title).toLowerCase().includes(q) ||
          safeString(p.goal).toLowerCase().includes(q) ||
          (Array.isArray(p.tags) ? p.tags : []).some(t => safeString(t).toLowerCase().includes(q))
        );
      })
    : [];

  const tryFetchWithTrailingSlash = async (url, opts) => {
    let res = await fetch(url, opts);
    if (res.status === 404 && !url.endsWith("/")) res = await fetch(url + "/", opts);
    return res;
  };

  const selectPlaybook = async (playbookSummary) => {
    const id = encodeURIComponent(String(playbookSummary.id));
    setMessage("");
    setSelectedId(playbookSummary.id);
    try {
      const res = await tryFetchWithTrailingSlash(`${API_BASE}/playbooks/${id}`, { method: "GET" });
      const full = res.ok ? await res.json() : playbookSummary;
      setForm({
        title: full.title || "",
        goal: full.goal || "",
        instructions: full.instructions || "",
        tags: (full.tags || []).join(", "),
        tools: (full.tools || []).join(", "),
        model: full.model || "",
      });
    } catch {
      setForm({
        title: playbookSummary.title || "",
        goal: playbookSummary.goal || "",
        instructions: playbookSummary.instructions || "",
        tags: (playbookSummary.tags || []).join(", "),
        tools: (playbookSummary.tools || []).join(", "),
        model: playbookSummary.model || "",
      });
    }
  };

  const resetForm = () => {
    setSelectedId(null);
    setForm({ title: "", goal: "", instructions: "", tags: "", tools: "", model: "" });
    setMessage("");
  };

  const savePlaybook = async () => {
    if (!form.title || !form.goal || !form.instructions) {
      setMessage("Please fill in title, goal, and instructions.");
      return;
    }
    const payload = {
      title: form.title,
      goal: form.goal,
      instructions: form.instructions,
      tags: form.tags.split(",").map(t => t.trim()).filter(Boolean),
      tools: (form.tools || "").split(",").map(t => t.trim()).filter(Boolean),
      model: (form.model || "").trim(),
    };
    const isUpdate = Boolean(selectedId);
    const safeId = isUpdate ? encodeURIComponent(String(selectedId)) : null;
    const baseUrl = isUpdate ? `${API_BASE}/playbooks/${safeId}` : `${API_BASE}/playbooks`;
    const commonOpts = { headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) };

    try {
      let res;
      if (isUpdate) {
        res = await tryFetchWithTrailingSlash(baseUrl, { ...commonOpts, method: "PATCH" });
        if (res.status === 404 || res.status === 405) {
          const getRes = await tryFetchWithTrailingSlash(baseUrl, { method: "GET" });
          const existing = getRes.ok ? await getRes.json().catch(() => ({})) : {};
          res = await tryFetchWithTrailingSlash(baseUrl, {
            method: "PUT",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ ...existing, ...payload }),
          });
        }
      } else {
        res = await tryFetchWithTrailingSlash(baseUrl, { ...commonOpts, method: "POST" });
      }
      if (!res.ok) {
        const text = await res.text().catch(() => "");
        setMessage(`Save failed: ${text || res.statusText}`);
        return;
      }
      setMessage(isUpdate ? "Playbook updated." : "Playbook created.");
      resetForm();
      loadPlaybooks();
    } catch (err) {
      setMessage(`Save error: ${err.message || err}`);
    }
  };

  const deletePlaybook = async (id) => {
    if (!window.confirm("Delete this playbook?")) return;
    const safeId = encodeURIComponent(String(id));
    try {
      const res = await tryFetchWithTrailingSlash(`${API_BASE}/playbooks/${safeId}`, { method: "DELETE" });
      if (!res.ok) {
        const text = await res.text().catch(() => "");
        setMessage(`Delete failed: ${text || res.statusText}`);
        return;
      }
      setMessage("Playbook deleted.");
      if (selectedId === id) resetForm();
      loadPlaybooks();
    } catch (err) {
      setMessage(`Delete error: ${err.message || err}`);
    }
  };

  const onDragStart = (e, id) => {
    dragItem.current = String(id);
    e.dataTransfer.effectAllowed = "move";
  };

  const onDragEnter = (e, id) => {
    dragOverItem.current = String(id);
    e.preventDefault();
  };

  const onDragOver = (e) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = "move";
  };

  const onDrop = async () => {
    if (!dragItem.current || dragItem.current === dragOverItem.current) return;

    const currentOrder = filteredPlaybooks.map(p => String(p.id));
    const fromIdx = currentOrder.indexOf(dragItem.current);
    const toIdx = currentOrder.indexOf(dragOverItem.current);
    if (fromIdx === -1 || toIdx === -1) return;

    // Guard: only a playbook with "main" in its title can occupy the first slot
    if (toIdx === 0 && fromIdx !== 0) {
      const dragged = filteredPlaybooks.find(p => String(p.id) === dragItem.current);
      if (!dragged || !dragged.title.toLowerCase().includes("main")) {
        setMessage("Only a playbook with 'main' in its title can be placed first.");
        dragItem.current = null;
        dragOverItem.current = null;
        return;
      }
    }

    const newFilteredOrder = [...currentOrder];
    newFilteredOrder.splice(fromIdx, 1);
    newFilteredOrder.splice(toIdx, 0, dragItem.current);

    // Optimistic UI update — reorder within filtered set, keep unfiltered playbooks intact
    setPlaybooks(prev => {
      const filteredSet = new Set(currentOrder);
      const filteredMap = Object.fromEntries(prev.filter(p => filteredSet.has(String(p.id))).map(p => [String(p.id), p]));
      const reorderedFiltered = newFilteredOrder.map(id => filteredMap[id]).filter(Boolean);
      // Merge: place unfiltered items back in their original relative positions
      const result = [];
      let fi = 0;
      for (const p of prev) {
        if (filteredSet.has(String(p.id))) {
          if (fi < reorderedFiltered.length) result.push(reorderedFiltered[fi++]);
        } else {
          result.push(p);
        }
      }
      return result;
    });

    dragItem.current = null;
    dragOverItem.current = null;

    // Send the full playbook order to the backend (filtered reorder merged with all IDs)
    try {
      await fetch(`${API_BASE}/playbooks/reorder`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ ids: newFilteredOrder }),
      });
    } catch (err) {
      console.error("Failed to persist order:", err);
      loadPlaybooks();
    }
  };

  return (
    <div style={{ flexGrow: 1 }}>
      <div style={{ display: "flex", gap: "1rem", alignItems: "stretch" }}>

        {/* Sidebar */}
        <aside style={{
          width: "35%",
          minWidth: "280px",
          background: "#161616",
          border: "1px solid #333",
          borderRadius: "12px",
          padding: "1rem"
        }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "1rem" }}>
            <h3 style={{ margin: 0, fontSize: "1rem" }}>Playbooks</h3>
            <button
              onClick={resetForm}
              style={{ padding: "0.35rem 0.75rem", background: "#007acc", color: "#fff", border: "none", borderRadius: "6px", cursor: "pointer" }}
            >
              New
            </button>
          </div>

          <input
            type="text"
            placeholder="Search playbooks..."
            value={search}
            onChange={e => setSearch(e.target.value)}
            style={{
              width: "100%",
              padding: "0.75rem",
              background: "#222",
              color: "#eee",
              border: "1px solid #333",
              borderRadius: "8px",
              marginBottom: "1rem",
              boxSizing: "border-box"
            }}
          />

          <div style={{ maxHeight: "calc(100vh - 240px)", overflowY: "auto" }}>
            {filteredPlaybooks.length === 0 ? (
              <p style={{ color: "#aaa" }}>No playbooks found.</p>
            ) : (
              filteredPlaybooks.map((p, idx) => {
                const isMain = idx === 0 && !search.trim();
                return (
                  <div
                    key={safeString(p.id)}
                    draggable
                    onDragStart={e => onDragStart(e, p.id)}
                    onDragEnter={e => onDragEnter(e, p.id)}
                    onDragOver={onDragOver}
                    onDrop={onDrop}
                    onClick={() => selectPlaybook(p)}
                    style={{
                      padding: "0.75rem 1rem",
                      marginBottom: "0.5rem",
                      borderRadius: "10px",
                      cursor: "grab",
                      background: selectedId === p.id ? "#262626" : "#1b1b1b",
                      border: selectedId === p.id
                        ? "1px solid #007acc"
                        : isMain
                          ? "1px solid #2a4a2a"
                          : "1px solid #2a2a2a",
                      display: "flex",
                      alignItems: "center",
                      gap: "0.75rem",
                      userSelect: "none",
                    }}
                  >
                    <span style={{ color: "#555", fontSize: "1rem", flexShrink: 0 }}>⠿</span>
                    <span style={{ color: "#eee", fontSize: "0.95rem", textAlign: "left", flexGrow: 1 }}>{p.title}</span>
                    {isMain && (
                      <span style={{
                        fontSize: "0.65rem",
                        fontWeight: "600",
                        color: "#4caf50",
                        background: "#1a2e1a",
                        border: "1px solid #2a4a2a",
                        borderRadius: "4px",
                        padding: "0.15rem 0.4rem",
                        flexShrink: 0,
                        letterSpacing: "0.05em",
                      }}>
                        MAIN
                      </span>
                    )}
                  </div>
                );
              })
            )}
          </div>
        </aside>

        {/* Editor */}
        <main style={{
          flexGrow: 1,
          background: "#161616",
          border: "1px solid #333",
          borderRadius: "12px",
          padding: "1rem"
        }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: "1rem", marginBottom: "1rem" }}>
            <div>
              <h3 style={{ margin: 0, fontSize: "1rem" }}>{selectedId ? "Edit Playbook" : "Create Playbook"}</h3>
              <p style={{ margin: "0.35rem 0 0", color: "#aaa", fontSize: "0.9rem" }}>
                Select a playbook on the left, then edit here.
              </p>
            </div>
            {selectedId && (
              <button
                onClick={() => deletePlaybook(selectedId)}
                style={{ padding: "0.5rem 0.9rem", background: "#b32f2f", color: "#fff", border: "none", borderRadius: "8px", cursor: "pointer" }}
              >
                Delete
              </button>
            )}
          </div>

          <div style={{ display: "grid", gap: "0.9rem" }}>
            <input
              type="text"
              placeholder="Title"
              value={form.title}
              onChange={e => setForm(prev => ({ ...prev, title: e.target.value }))}
              style={{ padding: "0.9rem", background: "#222", color: "#eee", border: "1px solid #333", borderRadius: "10px" }}
            />
            <input
              type="text"
              placeholder="Tags (comma separated)"
              value={form.tags}
              onChange={e => setForm(prev => ({ ...prev, tags: e.target.value }))}
              style={{ padding: "0.9rem", background: "#222", color: "#eee", border: "1px solid #333", borderRadius: "10px" }}
            />
            <input
              type="text"
              placeholder="Playbook tools: search_memory, … (render_preview auto-attaches on visual asks)"
              value={form.tools}
              onChange={e => setForm(prev => ({ ...prev, tools: e.target.value }))}
              style={{ padding: "0.9rem", background: "#222", color: "#eee", border: "1px solid #333", borderRadius: "10px" }}
            />
            <input
              type="text"
              placeholder="Model (blank = auto-select): e.g. mistral:latest"
              value={form.model}
              onChange={e => setForm(prev => ({ ...prev, model: e.target.value }))}
              style={{ padding: "0.9rem", background: "#222", color: "#eee", border: "1px solid #333", borderRadius: "10px" }}
            />
            <textarea
              rows={4}
              placeholder="Goal"
              value={form.goal}
              onChange={e => setForm(prev => ({ ...prev, goal: e.target.value }))}
              style={{ padding: "0.9rem", background: "#222", color: "#eee", border: "1px solid #333", borderRadius: "10px" }}
            />
            <textarea
              rows={10}
              placeholder="Instructions"
              value={form.instructions}
              onChange={e => setForm(prev => ({ ...prev, instructions: e.target.value }))}
              onKeyDown={e => {
                if (e.key === "Tab") {
                  e.preventDefault();
                  const ta = e.currentTarget;
                  const start = ta.selectionStart;
                  const end = ta.selectionEnd;
                  setForm(prev => {
                    const newVal = prev.instructions.slice(0, start) + "\t" + prev.instructions.slice(end);
                    setTimeout(() => { ta.selectionStart = ta.selectionEnd = start + 1; }, 0);
                    return { ...prev, instructions: newVal };
                  });
                }
              }}
              style={{ padding: "0.9rem", background: "#222", color: "#eee", border: "1px solid #333", borderRadius: "10px" }}
            />
          </div>

          <div style={{ marginTop: "1rem", display: "flex", gap: "0.75rem", flexWrap: "wrap" }}>
            <button
              onClick={savePlaybook}
              style={{ padding: "0.85rem 1.2rem", background: "#007acc", color: "#fff", border: "none", borderRadius: "8px", cursor: "pointer" }}
            >
              {selectedId ? "Update Playbook" : "Create Playbook"}
            </button>
            <button
              onClick={resetForm}
              style={{ padding: "0.85rem 1.2rem", background: "#444", color: "#fff", border: "none", borderRadius: "8px", cursor: "pointer" }}
            >
              Clear
            </button>
          </div>

          {message && (
            <div style={{ marginTop: "1rem", color: "#aaffaa" }}>{message}</div>
          )}
        </main>
      </div>
    </div>
  );
}