import { Coll, Collection, Collection2D } from "util/collection";

// If blank strings/ints is not enough
export const inputMapper = (inputs: string) => inputs;

function buildStacks(input: Collection<string>): Collection2D<string> {
  const stacks: Collection2D<string> = Coll();

  for (let i = 0; i < input[0].length / 4; i++) {
    stacks.push(Coll());
  }

  const lines = input.slice(0, input.length - 1).map((line) =>
    Coll(...line.split("")).partition(4).map((chars) => chars[1])
  );

  for (const line of lines) {
    for (let i = 0; i < line.length; i++) {
      if (line[i] !== " ") {
        stacks[i].push(line[i]);
      }
    }
  }

  for (const stack of stacks) {
    stack.reverse();
  }

  return stacks;
}

interface Move {
  amount: number;
  from: number;
  to: number;
}

function mapExpressions(input: Collection<string>): Collection<Move> {
  return input.map((line) => line.split(" ")).map((strs) => ({
    amount: parseInt(strs[1]),
    from: parseInt(strs[3]),
    to: parseInt(strs[5]),
  }));
}

export function solution1(inputs: Collection<string>): string {
  const [instructions, setup] = inputs.splitOnValue("");

  const stacks = buildStacks(setup);
  const expressions = mapExpressions(instructions);

  for (const { amount, from, to } of expressions) {
    const fromStack = stacks[from - 1];
    const toStack = stacks[to - 1];

    for (let i = 0; i < amount; i++) {
      toStack.push(fromStack.pop() as string);
    }
  }

  return stacks.map((s) => s.last).join("");
}

export function solution2(inputs: Collection<string>): string {
  const [instructions, setup] = inputs.splitOnValue("");

  const stacks = buildStacks(setup);
  const expressions = mapExpressions(instructions);

  for (const { amount, from, to } of expressions) {
    const fromStack = stacks[from - 1];
    const toStack = stacks[to - 1];

    toStack.push(...fromStack.splice(fromStack.length - amount, amount));
  }

  return stacks.map((s) => s.last).join("");
}
