/* global React */
const { useState: useStateLB, useMemo: useMemoLB } = React;

const PALETTE = [
  { kind: "prompt",       label: "PromptTemplate",     pyExpr: "prompt", desc: "Format messages from input vars" },
  { kind: "model",        label: "ChatModel",          pyExpr: "model",  desc: "LLM call (e.g. ChatOpenAI)" },
  { kind: "parser",       label: "StrOutputParser",    pyExpr: "StrOutputParser()", desc: "Extract .content as string" },
  { kind: "parser",       label: "JsonOutputParser",   pyExpr: "JsonOutputParser()", desc: "Parse JSON output" },
  { kind: "retriever",    label: "Retriever",          pyExpr: "retriever", desc: "Vector search → docs" },
  { kind: "tool",         label: "ToolNode",           pyExpr: "tools",  desc: "Run a bound tool" },
  { kind: "passthrough",  label: "RunnablePassthrough",pyExpr: "RunnablePassthrough()", desc: "Pass input untouched" },
  { kind: "passthrough",  label: "RunnableLambda",     pyExpr: "RunnableLambda(fn)",    desc: "Wrap a plain Python fn" },
];

const DEFAULT_CHAIN = [0, 1, 2]; // prompt | model | parser

function LCELBuilder() {
  const [chain, setChain] = useStateLB(DEFAULT_CHAIN);
  const [input, setInput] = useStateLB("explain agents in one sentence");

  const code = useMemoLB(() => {
    if (chain.length === 0) return "# Drop blocks below to compose a chain";
    const parts = chain.map(i => PALETTE[i].pyExpr);
    return `chain = ${parts.join(" | ")}\n\nresult = chain.invoke(${JSON.stringify(input)})`;
  }, [chain, input]);

  const output = useMemoLB(() => {
    if (chain.length === 0) return "▌ ready";
    const last = PALETTE[chain[chain.length - 1]];
    if (last.kind === "parser" && last.label === "JsonOutputParser") {
      return `{\n  "answer": "Agents are LLMs that loop: think, act with tools, observe, repeat.",\n  "confidence": 0.91\n}`;
    }
    if (last.kind === "model")  return `AIMessage(content='Agents are LLMs that loop: think, act with tools, observe, repeat.', ...)`;
    if (last.kind === "tool")   return `ToolMessage(name='get_weather', content='{"temp_c": 18.2}', ...)`;
    if (last.kind === "retriever") return `[Document(page_content='An agent uses an LLM as a reasoning engine...', metadata={...}), Document(...)]`;
    if (last.kind === "passthrough") return `${JSON.stringify(input)}`;
    // Default: parser/string
    return `'Agents are LLMs that loop: think, act with tools, observe, repeat.'`;
  }, [chain, input]);

  const add = (i) => setChain(c => [...c, i]);
  const remove = (idx) => setChain(c => c.filter((_, i) => i !== idx));
  const clear = () => setChain([]);
  const preset = (which) => {
    if (which === "rag") setChain([4, 0, 1, 2]);     // retriever | prompt | model | parser
    else if (which === "json") setChain([0, 1, 3]);  // prompt | model | json
    else setChain(DEFAULT_CHAIN);
  };

  return (
    <Diagram
      title="LCEL Pipe Builder · click to compose"
      controls={
        <>
          <button className="btn ghost" onClick={() => preset("basic")}>Basic</button>
          <button className="btn ghost" onClick={() => preset("rag")}>RAG</button>
          <button className="btn ghost" onClick={() => preset("json")}>JSON</button>
          <button className="btn ghost" onClick={clear}>Clear</button>
        </>
      }
    >
      <div className="lcel-builder">
        <div className={`lcel-canvas ${chain.length === 0 ? "empty" : ""}`}>
          {chain.length === 0 && "Click blocks below to add to your chain →"}
          {chain.map((i, idx) => (
            <React.Fragment key={idx}>
              {idx > 0 && <span className="lcel-pipe">|</span>}
              <span className={`lcel-block in-canvas ${PALETTE[i].kind}`}
                    onClick={() => remove(idx)} title="Click to remove">
                <span className="dot" />
                {PALETTE[i].label}
              </span>
            </React.Fragment>
          ))}
        </div>

        <h4 className="mini-title" style={{ marginTop: 16 }}>Add a runnable</h4>
        <div className="lcel-palette">
          {PALETTE.map((p, i) => (
            <span key={i} className={`lcel-block ${p.kind}`} onClick={() => add(i)}>
              <span className="dot" />
              + {p.label}
            </span>
          ))}
        </div>

        <h4 className="mini-title" style={{ marginTop: 18 }}>Composed code</h4>
        <CodeBlock file="chain.py">{code}</CodeBlock>

        <h4 className="mini-title">Simulated output</h4>
        <div className="lcel-output">{output}</div>

        <p style={{ fontSize: 12.5, color: "var(--ink-3)", marginTop: 14, marginBottom: 0 }}>
          Every block is a <code>Runnable</code> — it implements <code>.invoke()</code>, <code>.stream()</code>, <code>.batch()</code>, and <code>.ainvoke()</code>.
          The pipe is just <code>RunnableSequence</code>; left's output becomes right's input.
        </p>
      </div>
    </Diagram>
  );
}

window.LCELBuilder = LCELBuilder;
