#include <stdio.h>

#include "teyaku.h"
#include "card.h"

SetTeyaku calculate_set_teyaku(const Hand h) {
  int month_counts[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  int month_stands[12] = { 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1 };
  for (int i = 0; i < h.count; i++) {
    Card c = *h.cards[i];
    month_counts[c.month]++;
  }

  int triplets = 0, standing_triplets = 0, pairs = 0, four_of_a_kind = 0;
  for (int i = 0; i < 12; i++) {
    if (month_counts[i] == 4) {
      four_of_a_kind++;
    } else if (month_counts[i] == 3) {
      if (month_stands[i]) standing_triplets++; // TODO Pawlonia is weird
      else triplets++;
    } else if (month_counts[i] == 2) {
      pairs++;
    }
  }
  int total_triplets = triplets + standing_triplets;

  if (four_of_a_kind && total_triplets) return FOUR_THREE;
  else if (four_of_a_kind && pairs) return ONE_TWO_FOUR;
  else if (standing_triplets == 2) return TWO_STANDING_TRIPLETS;
  else if (total_triplets && pairs == 2) return TRIPLET_AND_TWO_PAIRS;
  else if (triplets == 1 && standing_triplets == 1) return TRIPLET_AND_STANDING_TRIPLET;
  else if (four_of_a_kind) return FOUR_OF_A_KIND;
  else if (triplets == 2) return TWO_TRIPLETS;
  else if (pairs == 3) return THREE_PAIRS;
  else if (standing_triplets) return STANDING_TRIPLET;
  else if (triplets) return TRIPLET;

  return SET_TEYAKU_NONE;
}

ChaffTeyaku calculate_chaff_teyaku(const Hand h) {
  int ribbons = 0;
  int animals = 0;
  int brights = 0;
  int chaff = 0;

  for (int i = 0; i < h.count; i++) {
    Card c = *h.cards[i];
    if (c.month == NOVEMBER) chaff++; // November cards are all counted as chaff here
    else if (c.type == BRIGHT) brights++;
    else if (c.type == RIBBON) ribbons++;
    else if (c.type == ANIMAL) animals++;
    else chaff++;
  }

  if (chaff == 7) return EMPTY_HAND;
  else if (chaff == 6 && brights == 1) return ONE_BRIGHT;
  else if (chaff == 6 && animals == 1) return ONE_ANIMAL;
  else if (chaff == 6 && ribbons == 1) return ONE_RIBBON;
  else if (ribbons >= 2 && chaff == 7 - ribbons) return CHAFF_TEYAKU_RED;

  return CHAFF_TEYAKU_NONE;
}

static int set_teyaku_points_array[11] = { 0, 2, 3, 6, 7, 8, 4, 6, 7, 8, 20 };
static char *set_teyaku_english_array[11] = { "None", "Triplet", "Standing Triplet", "Two Triplets", "Triplet and Standing Triplet", "Two Standing Triplets", "Three Pairs", "Four of a Kind", "Triplet and Two Pairs", "One-Two-Four", "Four-Three" };
static int chaff_teyaku_points_array[6] = { 0, 2, 3, 3, 4, 4 };
static char *chaff_teyaku_english_array[6] = { "None", "Red", "One Ribbon", "One Animal", "One Bright", "Empty Hand" };

int set_teyaku_points(SetTeyaku st) {
  return set_teyaku_points_array[st];
}

int chaff_teyaku_points(ChaffTeyaku ct) {
  return chaff_teyaku_points_array[ct];
}

char *set_teyaku_english(SetTeyaku st) {
  return set_teyaku_english_array[st];
}

char *chaff_teyaku_english(ChaffTeyaku ct) {
  return chaff_teyaku_english_array[ct];
}

void calculate_teyaku(const Hand h, Teyaku *t) {
  t->chaff = calculate_chaff_teyaku(h);
  t->set = calculate_set_teyaku(h);
  t->calculated = true;
}

void teyaku_to_string(Teyaku *t, char *str) {
  int set_points = set_teyaku_points(t->set);
  int chaff_points = chaff_teyaku_points(t->chaff);
  sprintf(str, "Set: %s(%d) / Chaff: %s(%d) / Total: %d", set_teyaku_english(t->set), set_points, chaff_teyaku_english(t->chaff), chaff_points, set_points + chaff_points);
}