import AOC

aoc 2021, 13 do
  def input(input_string \\ input_string()) do
    [dots_string, folds_string] =
      input_string
      |> String.split("\n\n", trim: true)

    dots =
      dots_string
      |> String.split("\n", trim: true)
      |> Enum.map(fn line ->
        [x, y] =
          String.split(line, ",")
          |> Enum.map(&String.to_integer/1)

        {x, y}
      end)
      |> MapSet.new()

    folds =
      folds_string
      |> String.split("\n", trim: true)
      |> Enum.map(fn
        "fold along y=" <> y -> {:y, String.to_integer(y)}
        "fold along x=" <> x -> {:x, String.to_integer(x)}
      end)

    {dots, folds}
  end

  def do_fold({:y, line}, dots) do
    for {x, y} <- dots, into: MapSet.new() do
      if y > line do
        {x, line - (y - line)}
      else
        {x, y}
      end
    end
  end

  def do_fold({:x, line}, dots) do
    for {x, y} <- dots, into: MapSet.new() do
      if x > line do
        {line - (x - line), y}
      else
        {x, y}
      end
    end
  end

  def p1 do
    {dots, [fold | _folds]} = input()

    do_fold(fold, dots) |> MapSet.size()
  end

  def p2 do
    {dots, folds} = input()

    final_dots = Enum.reduce(folds, dots, &do_fold/2)

    max_x = final_dots |> Enum.map(&elem(&1, 0)) |> Enum.max()
    max_y = final_dots |> Enum.map(&elem(&1, 1)) |> Enum.max()

    for x <- 0..max_x, into: "" do
      for y <- 0..max_y, into: "" do
        if MapSet.member?(final_dots, {x, y}), do: "#", else: "."
      end <> "\n"
    end
    |> IO.puts()
  end
end