#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#include "../../lib/aoc.h"

typedef char Towel[10];

typedef struct Towels {
  Towel towels[2000];
  int towels_count;
  AocHashmap *map;
} Towels;

bool towels_valid_design(Towels *t, char *design) {
  if (strlen(design) == 0) return true;
  for (int i = 0; i < t->towels_count; i++) {
    if (strstr(design, t->towels[i]) == design) {
      if (towels_valid_design(t, design + strlen(t->towels[i]))) return true;
    }
  }
  return false;
}

long towels_valid_designs(Towels *t, char *design) {
  AocHashmapNode *memo = aoc_hashmap_get(t->map, design);
  if (memo != NULL) return memo->value;

  if (strlen(design) == 0) return 1;

  long valid_designs = 0;
  for (int i = 0; i < t->towels_count; i++) {
    if (strstr(design, t->towels[i]) == design) {
      valid_designs += towels_valid_designs(t, design + strlen(t->towels[i]));
    }
  }

  aoc_hashmap_put(t->map, design, valid_designs);

  return valid_designs;
}

int main() {
  char *line;

  Towels towels;
  towels.towels_count = 0;
  towels.map = malloc(sizeof(AocHashmap));
  for (int i = 0; i < AOC_HASHMAP_RADIX; i++) {
    towels.map->buckets[i] = NULL;
  }


  line = aoc_read_line();
  char *token = strtok(line, ", ");
  while (token != NULL) {
    strcpy(towels.towels[towels.towels_count++], token);
    token = strtok(NULL, ", ");
  }

  aoc_read_line(); // blank line

  int valid_single_designs = 0;
  long valid_multi_designs = 0;
  while ((line = aoc_read_line()) != NULL) {
    if (towels_valid_design(&towels, line)) valid_single_designs++;
    valid_multi_designs += towels_valid_designs(&towels, line);
  }

  printf("Part 1: %d\n", valid_single_designs);
  printf("Part 2: %ld\n", valid_multi_designs);

  aoc_free();
  exit(0);
}