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

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

typedef struct Report {
  int *levels;
  int size;
  int skip;
} Report;

bool report_increasing(Report *report) {
  int current = report->levels[0];
  int i = 1;
  if (report->skip == 0) {
    current = report->levels[1];
    i = 2;
  }
  for (; i < report->size; i++) {
    if (i == report->skip) continue;
    int next = report->levels[i];
    if (next <= current) return false;
    current = next;
  }
  return true;
}

bool report_decreasing(Report *report) {
  int current = report->levels[0];
  int i = 1;
  if (report->skip == 0) {
    current = report->levels[1];
    i = 2;
  }
  for (; i < report->size; i++) {
    if (i == report->skip) continue;
    int next = report->levels[i];
    if (next >= current) return false;
    current = next;
  }
  return true;
}

bool report_changing_slowly(Report *report) {
  int current = report->levels[0];
  int i = 1;
  if (report->skip == 0) {
    current = report->levels[1];
    i = 2;
  }
  for (; i < report->size; i++) {
    if (i == report->skip) continue;
    int next = report->levels[i];
    if (abs(next - current) > 3) return false;
    current = next;
  }
  return true;
}

bool report_safe_with_skips(Report *report) {
  for (int i = -1; i < report->size; i++) {
    report->skip = i;
    if ((report_increasing(report) || report_decreasing(report)) && report_changing_slowly(report)) {
      return true;
    }
  }
  return false;
}

bool report_safe(Report *report) {
  report->skip = -1;
  return (report_increasing(report) || report_decreasing(report)) && report_changing_slowly(report);
}

void populate_report(Report *report, char *line) {
  report->size = 0;
  char *level = strtok(line, " ");
  while (level != NULL) {
    report->levels[report->size] = atoi(level);
    report->size++;
    level = strtok(NULL, " ");
  }
}

int main() {
  char *line;

  Report report;
  report.levels = malloc(20 * sizeof(int));
  report.size = 0;

  int safe_report_count = 0;
  int safe_skip_report_count = 0;

  while ((line = aoc_read_line()) != NULL) {
    populate_report(&report, line);
    if (report_safe(&report)) safe_report_count += 1;
    if (report_safe_with_skips(&report)) safe_skip_report_count += 1;
  }

  printf("Part 1: %d\n", safe_report_count);
  printf("Part 2: %d\n", safe_skip_report_count);

  aoc_free();
  return 0;
}