<!-- eslint-disable vue/multi-word-component-names -->
<template>
  <div class="card">
    <header class="card-header is-unselectable" style="cursor: pointer">
      <p class="card-header-title" @click="toggle">{{ header }}</p>

      <p v-if="refreshable" class="card-header-icon px-0">
        <BulmaButton class="is-small is-primary" @click="refresh">
          <FontAwesomeIcon
            :icon="['fas', 'arrows-rotate']"
            :spin="is_open && state === 'loading'"
          />
        </BulmaButton>
      </p>

      <button class="card-header-icon" @click="toggle">
        <span class="icon">
          <FontAwesomeIcon
            :icon="['fas', is_open ? 'angle-down' : 'angle-right']"
          />
        </span>
      </button>
    </header>

    <template v-if="is_open">
      <div v-if="state === 'loading'" class="card-content">
        <progress class="progress is-primary" />
      </div>
      <div
        v-else-if="state === 'failed'"
        class="card-content has-text-danger has-text-centered"
      >
        <span class="icon is-large">
          <FontAwesomeIcon :icon="['fas', 'ban']" size="3x" />
        </span>
      </div>
      <slot v-else name="default" />
    </template>
  </div>
</template>

<script setup lang="ts">
import { ref } from "vue";

import BulmaButton from "./Button.vue";

withDefaults(
  defineProps<{
    header: string;
    refreshable?: boolean;
  }>(),
  { refreshable: false },
);

const emit = defineEmits<{
  (event: "open", ready: () => void, fail: () => void): void;
}>();

const is_open = ref(false);
const state = ref<"loading" | "ready" | "failed">("loading");

function toggle() {
  is_open.value = !is_open.value;

  if (is_open.value) {
    state.value = "loading";

    emit(
      "open",
      () => (state.value = "ready"),
      () => (state.value = "failed"),
    );
  }
}

function refresh() {
  is_open.value = false;
  toggle();
}
</script>

<style scoped>
div.card:not(:last-child) {
  margin-bottom: 1.5rem;
}
</style>
