import React, { ReactNode, useEffect, useMemo, useRef, useState } from "react";
import "./Explorer.css";
import { Highlight } from "./highlight";
import { buildShadow } from "./shadow";
import OrgAst, { OrgNodeReference } from "./OrgAst";
import { parse_org } from "../../organic/target/wasm32-unknown-unknown/js/wasm";

const default_org_source: string = `* Welcome to the Organic Ast Explorer!

Type your Org [fn:1] source in this text box, and it will be parsed by Organic [fn:2] that has been compiled into wasm and embedded in this page. The resulting AST will be rendered to the right.

In the AST on the right, you can:

1. Click on an AST node to highlight the corresponding portion of the Org source on the left.
2. Expand/Collapse the children, properties, and standard properties.

* Footnotes

[fn:1] https://orgmode.org/

[fn:2] https://code.fizz.buzz/talexander/organic
`;

function Explorer({ defaultValue = default_org_source }) {
  function handleChange(event: React.ChangeEvent<HTMLTextAreaElement>) {
    setValue(event.target.value);
    clearHighlights();
  }

  const [value, setValue] = useState(defaultValue);

  const [highlights, setHighlights] = useState<Array<Highlight>>([]);

  const astTree = useMemo(() => {
    const astTree = parse_org(value);
    console.log(JSON.stringify(astTree));
    return astTree;
  }, [value]);

  function setHighlight(nodes: OrgNodeReference[]) {
    let new_highlights = nodes.map((node: OrgNodeReference) => {
      return new Highlight(node.start - 1, node.end - 1);
    });
    new_highlights.sort(function (a, b) {
      if (a.start < b.start) return -1;
      if (a.start > b.start) return 1;
      return 0;
    });
    setHighlights(new_highlights);
  }

  function addHighlight(start: number, end: number) {
    let new_highlights = [...highlights, new Highlight(start, end)];
    new_highlights.sort(function (a, b) {
      if (a.start < b.start) return -1;
      if (a.start > b.start) return 1;
      return 0;
    });
    setHighlights(new_highlights);
  }

  function clearHighlights() {
    setHighlights([]);
  }

  const textAreaRef = useRef<HTMLTextAreaElement>(null);
  const shadowRef = useRef<HTMLDivElement>(null);
  function onTextAreaScroll() {
    if (shadowRef.current !== null && textAreaRef.current !== null) {
      const textAreaScrollTop = textAreaRef.current.scrollTop;
      shadowRef.current.scrollTop = textAreaScrollTop;
    }
  }

  useEffect(() => {
    // Make sure the text area and shadow div start out in sync.
    onTextAreaScroll();
  }, []);

  return (
    <div className="Explorer">
      <div className="Explorer-textwrapper">
        <textarea
          ref={textAreaRef}
          onChange={handleChange}
          className="Explorer-textarea"
          value={value}
          onScroll={onTextAreaScroll}
        />
        <div ref={shadowRef} className="Explorer-underlay">
          {buildShadow(highlights, value)}
          <br />
        </div>
      </div>
      <OrgAst
        setHighlight={setHighlight}
        clearHighlights={clearHighlights}
        value={value}
        astTree={astTree}
      />
    </div>
  );
}

export default Explorer;
