import { createSignal } from "solid-js";
import { Digith } from "src/ui/Digith";
import { useProgram } from "src/ui/ProgramProvider";
import { CodeEditor } from "src/ui/Component/CodeEditor";
import { sourceText } from "source-region";
import { Program } from "src/lang/program";
import { V, Validation, letValidate } from "src/ui/validation";
import { validateExprRaw, validateNameRaw, validateParamsRaw } from "src/ui/validation/helpers";
import { spawnFunctionDigith } from "src/ui/Scrowl/scrowlStore";
import { DigithError } from "src/ui/Digith/DigithError";

type Input = {
  raw_name: string,
  raw_params: string,
  raw_body: string,
}

const validator: Validation<Input, Program.CreateFunction, DigithError> = letValidate(
  (input) =>({
    name: V.elseErr(validateNameRaw(input.raw_name), err =>({
      payload: { tag: "Parse", err, src: sourceText(input.raw_name).fullRegion() },
      ids: ["name"],
      tags: ["footer"],
      config: { title: "Function Name", display: "flat" },
    })),
    parameters: V.elseErr(validateParamsRaw(input.raw_params), err => ({
      payload: { tag: "Parse", err, src: sourceText(input.raw_params).fullRegion() },
      ids: ["params"],
      tags: ["footer"],
      config: { title: "Parameters", display: "flat" },
    })),
    body: V.elseErr(validateExprRaw(input.raw_body), err => ({
      payload: { tag: "Parse", err, src: sourceText(input.raw_body).fullRegion() },
      ids: ["body"],
      tags: ["footer"],
      config: { title: "Function Body", display: "flat" },
    })),
  }),
  (fields, input) => {
    const createFunction: Program.CreateFunction = {
      name: fields.name,
      parameters: fields.parameters,
      body: fields.body,
      raw_parameters: input.raw_params,
      raw_body: input.raw_body,
    };
    return V.ok(createFunction);
})

export function NewFunctionDraftDigith(props: { draft: Digith.NewFunctionDraft }) {
  const program = useProgram();

  const [name, setName] = createSignal(props.draft.raw_name);
  const [params, setParams] = createSignal(props.draft.raw_parameters);
  const [body, setBody] = createSignal(props.draft.raw_body);

  const [errors, setErrors] = createSignal<DigithError[]>([]);

  function handleCommit() {
    setErrors([]);
    const validRes = validator({ raw_name: name(), raw_params: params(), raw_body: body() });
    if (validRes.tag === "errors") {
      setErrors(validRes.errors);
      return;
    }
    const createFunction = validRes.value;

    const programRes = Program.registerFunction(program, createFunction);
    if (programRes.tag === "error") {
      setErrors([{
        payload: { tag: "Program", err: programRes.error },
        ids: ["program"],
        tags: ["footer"],
        config: { title: "Registration Failed" },
      }]);
      return;
    }
    const fnName = programRes.value;

    spawnFunctionDigith(program, fnName, props.draft.id);
  };

  return (
    <article>
      <header><strong>Fn (Draft)</strong></header>

      <div class="grid">
        <label>
          Name
          <input 
            type="text" 
            placeholder="my_func" 
            value={name()} 
            onInput={(e) => setName(e.currentTarget.value)} 
          />
        </label>
        <label>
          Parameters (comma separated)
          <input 
            type="text" 
            placeholder="x, y" 
            value={params()} 
            onInput={(e) => setParams(e.currentTarget.value)} 
          />
        </label>
      </div>

      <label>Body</label>
      <CodeEditor 
        value={body()} 
        onUpdate={setBody} 
        onRun={handleCommit} 
      />

      <footer>
        <button class="primary" onClick={handleCommit}>Commit</button>
      </footer>

      <div style={{ "margin-top": "1rem" }}>
        <DigithError.ByTag errors={errors()} tag="footer" />
      </div>
    </article>
  );
}

