import { createSignal, Match, Switch } from 'solid-js';
import { useProgram } from 'src/ui/ProgramProvider';
import { eval_start } from 'src/lang/eval/evaluator';
import { Value } from 'src/lang/eval/value';
import { RuntimeError } from 'src/lang/eval/error';
import { SourceRegion, SourceText, sourceText } from 'source-region';
import { ParseError, parseExpr } from 'src/lang/parser/parser';
import { ShowParseError } from 'src/ui/Component/ParseError';
import { Val } from 'src/ui/Component/Value';
import { CodeEditor } from 'src/ui/Component/CodeEditor';

namespace ReplResult {
  export type Idle =
    { tag: "idle" }
  export type Success =
    { tag: "success", value: Value }
  export type Parse_Error =
    { tag: "parse_error", text: SourceRegion, err: ParseError }
  export type Runtime_Error =
    { tag: "runtime_error", err: RuntimeError }
}

type ReplResult =
  | ReplResult.Idle
  | ReplResult.Success
  | ReplResult.Parse_Error
  | ReplResult.Runtime_Error


export function ExprREPL() {
  const program = useProgram();

  const [input, setInput] = createSignal("");

  const [result, setResult] = createSignal<ReplResult>({ tag: "idle" });

  function runExecution() {
    const raw = input();
    if (input().trim() === "") {
      return;
    }
    const text = sourceText(raw).fullRegion();
    const parseResult = parseExpr(text);

    if (parseResult.tag === "error") {
      setResult({ tag: "parse_error", text: text, err: parseResult.error });
    } else {
      const evalResult = eval_start(program, parseResult.value);
      if (evalResult.tag === "ok") {
        setResult({ tag: "success", value: evalResult.value });
      } else {
        setResult({ tag: "runtime_error", err: evalResult.error });
      }
    }
  }

  return (
    <section>
      <CodeEditor 
        value={input()} 
        onUpdate={setInput} 
        onRun={runExecution} 
      />

      <button onClick={runExecution}>Run</button>
      
      <div style={{ "margin-top": "1rem" }}>
        <Switch>
          <Match when={result().tag === "idle"}>
            { "" }
          </Match>
          <Match when={result().tag === "success" && result() as ReplResult.Success }>
            {(res) => (
              <article>
                <header>Result</header>
                <Val value={ res().value } />
              </article>
            )}
          </Match>
          <Match when={result().tag === "parse_error" && result() as ReplResult.Parse_Error }>
            {(res) => (
              <ShowParseError text={res().text} err={res().err} />
            )}
          </Match>
            <Match when={result().tag === "runtime_error" && result() as ReplResult.Runtime_Error }>
              {(res) => (
                <article style={{ "border-color": "var(--pico-del-color)" }}>
                  <header style={{ color: "var(--pico-del-color)" }}>Runtime Error</header>
                  <pre>{JSON.stringify(res().err, null, 2)}</pre>
                </article>
              )}
            </Match>
        </Switch>
      </div>

    </section>
  );
}

