import gleam/int
import gleam/set
import gleam/list.{map}
import gleam/iterator
import gleam/string

type Rucksack =
  #(List(String), List(String))

pub fn pt_1(input: String) -> Int {
  string.split(input, on: "\n")
  |> map(string.to_graphemes)
  |> map(split_in_half)
  |> map(common_item)
  |> map(priority)
  |> int.sum
}

pub fn pt_2(input: String) -> Int {
  string.split(input, on: "\n")
  |> map(string.to_graphemes)
  |> iterator.from_list
  |> iterator.sized_chunk(3)
  |> iterator.map(common_item_pt2)
  |> iterator.map(priority)
  |> iterator.fold(0, fn(sum, prio) { sum + prio })
}

fn split_in_half(l: List(String)) -> Rucksack {
  list.split(l, at: list.length(l) / 2)
}

fn common_item(rucksack: Rucksack) -> String {
  let one = set.from_list(rucksack.0)
  let two = set.from_list(rucksack.1)
  let inter = set.intersection(one, two)
  assert 1 = set.size(inter)
  assert Ok(common) =
    inter
    |> set.to_list
    |> list.first
  common
}

fn common_item_pt2(sacks: List(List(String))) -> String {
  assert Ok(inter) =
    sacks
    |> map(set.from_list)
    |> list.reduce(set.intersection)
  assert 1 = set.size(inter)
  assert Ok(common) =
    inter
    |> set.to_list
    |> list.first
  common
}

// Lowercase item types a through z have priorities 1 through 26.
// Uppercase item types A through Z have priorities 27 through 52.
// I can't find a way to get a codepoint or match on a range with Gleam so this
// will have to do.
fn priority(item: String) -> Int {
  // case <<item:utf8>> {
  //   <<a:utf8_codepoint>> -> a
  // }
  case item {
    "a" -> 1
    "b" -> 2
    "c" -> 3
    "d" -> 4
    "e" -> 5
    "f" -> 6
    "g" -> 7
    "h" -> 8
    "i" -> 9
    "j" -> 10
    "k" -> 11
    "l" -> 12
    "m" -> 13
    "n" -> 14
    "o" -> 15
    "p" -> 16
    "q" -> 17
    "r" -> 18
    "s" -> 19
    "t" -> 20
    "u" -> 21
    "v" -> 22
    "w" -> 23
    "x" -> 24
    "y" -> 25
    "z" -> 26
    "A" -> 27
    "B" -> 28
    "C" -> 29
    "D" -> 30
    "E" -> 31
    "F" -> 32
    "G" -> 33
    "H" -> 34
    "I" -> 35
    "J" -> 36
    "K" -> 37
    "L" -> 38
    "M" -> 39
    "N" -> 40
    "O" -> 41
    "P" -> 42
    "Q" -> 43
    "R" -> 44
    "S" -> 45
    "T" -> 46
    "U" -> 47
    "V" -> 48
    "W" -> 49
    "X" -> 50
    "Y" -> 51
    "Z" -> 52
  }
}