#include <git2.h>
#include "git_repo.h"
#include "git_repo_refs.h"

#include "../templ/duc_git_repo_refs.h"

static orb_rc_t fetch(orb_module_t *self) {
  duc_git_repo_refs_t *data = self->data;
  git_repo_refs_param_list_t *param_list = self->param_list;
  if (!param_list) return ORB_FATAL(1);
  if (!param_list->repo) return ORB_FATAL(2);
  data->repo = param_list->repo;
  git_reference_iterator *iter = NULL;
  git_reference *ref_handle = NULL;
  git_reference_iterator_new(&iter, param_list->repo->handle);
  while (git_reference_next(&ref_handle, iter) == 0) {
    data->ref_list = realloc(data->ref_list, sizeof(git_repo_ref_t) * (data->ref_list_len + 1));
    git_repo_ref_t *ref = &data->ref_list[data->ref_list_len];
    memset(ref, 0, sizeof(git_repo_ref_t));
    const git_oid *oid = git_reference_target(ref_handle);
    char oid_str[GIT_OID_HEXSZ + 1];
    git_oid_tostr(oid_str, sizeof(oid_str), oid);
    ref->oid = strdup(oid_str);
    const char *ref_name = git_reference_name(ref_handle);
    if (git_reference_is_branch(ref_handle)) {
      ref->name = strdup(ref_name + strlen("refs/heads/"));
      ref->type = "branch";
    }
    if (git_reference_is_tag(ref_handle)) {
      ref->name = strdup(ref_name + strlen("refs/tags/"));
      ref->type = "tag";
    }
    if (git_reference_is_remote(ref_handle)) {
      ref->name = strdup(ref_name + strlen("refs/remotes/"));
      ref->type = "remote";
    }
    if (!ref->name) {
      ref->name = strdup(ref_name);
    }
    git_reference_free(ref_handle);
    data->ref_list_len++;
  }
  git_reference_iterator_free(iter);
  return ORB_OK;
}

static orb_rc_t render(orb_module_t *self, void *out) {
  return ORB_ERR(duc_git_repo_refs_render(out, (duc_git_repo_refs_t *) self->data));
}

static void cleanup(orb_module_t *self) {
  duc_git_repo_refs_t *data = self->data;
  if (data->ref_list && data->ref_list_len > 0) {
    for (size_t i = 0; i < data->ref_list_len; i++) {
      git_repo_ref_t *ref = &data->ref_list[i];
      free(ref->oid);
      free(ref->name);
    }
    free(data->ref_list);
    data->ref_list = NULL;
    data->ref_list_len = 0;
  }
}

const orb_module_type_t GIT_REPO_REFS_TYPE = {
  .size = sizeof(duc_git_repo_refs_t),
  .fetch = fetch,
  .render = render,
  .cleanup = cleanup,
};
