import { assert } from "chai";
import { bReduce } from "../operations";
import { purgeAstCache } from "../util";
import { parseTerm } from "../parser";
import { parse } from "ts-node";

describe("Beta Reductions", function () {
  it("Beta reduces a redex", function () {
    const ast = {
      type: "application",
      left: {
        type: "function",
        argument: "a",
        body: { type: "variable", name: "a" },
      },
      right: { type: "variable", name: "b" },
    };
    const expected = { type: "variable", name: "b" };
  });

  it("Avoids name conflicts when executing beta reductions", function () {
    // TODO: make this more robust with canonization, so it's not tied to specific implementation.
    const ast = {
      type: "application",
      left: {
        type: "function",
        argument: "a",
        body: {
          type: "function",
          argument: "b",
          body: {
            type: "application",
            left: { type: "variable", name: "a" },
            right: { type: "variable", name: "b" },
          },
        },
      },
      right: { type: "variable", name: "b" },
    };
    const expected = {
      type: "function",
      argument: "ε₁",
      body: {
        type: "application",
        left: { type: "variable", name: "b" },
        right: { type: "variable", name: "ε₁" },
      },
    };
    assert.deepEqual(purgeAstCache(bReduce(ast)), expected);
  });

  it("Avoids name conflicts when first chosen name is shadowed in an inner scope", () => {
    const ast = {
      type: "application",
      left: {
        type: "function",
        argument: "a",
        body: {
          type: "function",
          argument: "ε₁",
          body: {
            type: "application",
            left: {
              type: "variable",
              name: "a",
            },
            right: {
              type: "variable",
              name: "ε₁",
            },
          },
        },
      },
      right: {
        type: "variable",
        name: "ε₁",
      },
    };
    const expected = {
      type: "function",
      argument: "ε₂",
      body: {
        type: "application",
        left: {
          type: "variable",
          name: "ε₁",
        },
        right: {
          type: "variable",
          name: "ε₂",
        },
      },
    };
    assert.deepEqual(purgeAstCache(bReduce(ast)), expected);
  });

  it("Avoids name conflicts when first chosen name conflicts with free var in replacer", () => {
    const ast = {
      type: "application",
      left: {
        type: "function",
        argument: "a",
        body: {
          type: "function",
          argument: "b",
          body: {
            type: "application",
            left: {
              type: "variable",
              name: "a",
            },
            right: {
              type: "variable",
              name: "b",
            },
          },
        },
      },
      right: {
        type: "application",
        left: {
          type: "variable",
          name: "b",
        },
        right: {
          type: "variable",
          name: "ε₁",
        },
      },
    };
    const expected = {
      type: "function",
      argument: "ε₂",
      body: {
        type: "application",
        left: {
          type: "application",
          left: {
            type: "variable",
            name: "b",
          },
          right: {
            type: "variable",
            name: "ε₁",
          },
        },
        right: {
          type: "variable",
          name: "ε₂",
        },
      },
    };
    assert.deepEqual(purgeAstCache(bReduce(ast)), expected);
  });

  it("Avoids name conflicts when there are conflicting free vars in both", () => {
    const ast = {
      type: "application",
      left: {
        type: "function",
        argument: "a",
        body: {
          type: "function",
          argument: "ε₁",
          body: {
            type: "application",
            left: {
              type: "application",
              left: {
                type: "variable",
                name: "a",
              },
              right: {
                type: "variable",
                name: "ε₁",
              },
            },
            right: {
              type: "variable",
              name: "ε₂",
            },
          },
        },
      },
      right: {
        type: "variable",
        name: "ε₁",
      },
    };
    const expected = {
      type: "function",
      argument: "ε₃",
      body: {
        type: "application",
        left: {
          type: "application",
          left: {
            type: "variable",
            name: "ε₁",
          },
          right: {
            type: "variable",
            name: "ε₃",
          },
        },
        right: {
          type: "variable",
          name: "ε₂",
        },
      },
    };
    assert.deepEqual(purgeAstCache(bReduce(ast)), expected);
  });

  it("avoids name conflict in this specific weird case", () => {
    const ast = {
      type: "application",
      left: {
        type: "function",
        argument: "ε₁",
        body: {
          type: "function",
          argument: "a",
          body: {
            type: "function",
            argument: "ε₁",
            body: { type: "variable", name: "a" },
          },
        },
      },
      right: { type: "variable", name: "a" },
    };
    const expected = {
      type: "function",
      argument: "ε₁",
      body: {
        type: "function",
        argument: "ε₂",
        body: { type: "variable", name: "ε₁" },
      },
    };
    console.log(JSON.stringify(parseTerm("λε₁.λb.ε₁")));
    assert.deepEqual(purgeAstCache(bReduce(ast)), expected);
  });
});

@@ -148,41 +148,8 @@
 er%22;
-%0Aimport %7B parse %7D from %22ts-node%22;
 %0A%0Ade
@@ -502,16 +502,77 @@
  %22b%22 %7D;%0A
+    assert.deepEqual(purgeAstCache(bReduce(ast)), expected);%0A
   %7D);%0A%0A 
@@ -5005,16 +5005,20 @@
 in this 
+odd 
 specific
@@ -5022,14 +5022,8 @@
 fic 
-weird 
 case
@@ -5625,65 +5625,8 @@
  %7D;%0A
-    console.log(JSON.stringify(parseTerm(%22%CE%BB%CE%B5%E2%82%81.%CE%BBb.%CE%B5%E2%82%81%22)));%0A
     

fix up test a little