<script setup lang="ts">
import {ref, defineProps, defineEmits, watch, computed, onMounted, Component} from 'vue';
import '@creativebulma/bulma-divider/dist/bulma-divider.min.css';
const props = defineProps({
  label: {
    type: Object as () => {
      text: string|null;
      classes?: Array<string>;
      max_length?: number;
    },
    default: () => ({
      text: null,
      classes: [],
      max_length: null
    })
  },
  visibility: {
    type: Object as () => {
      icon: boolean;
      dropdown: boolean;
    },
    default: () => ({
      icon: true,
      dropdown: true
    })
  },
  is_narrow: {
    type: Boolean,
    default: false
  },
  color_class: {
    type: String,
    default: "has-text-grey"
  },
  is_loading: {
    type: Boolean,
    default: false
  },
  icon_class: {
    type: String,
    default: "fas fa-circle"
  },
  error_icon_class: {
    type: String,
    default: "fas fa-exclamation-triangle"
  },
  error_class: {
    type: String,
    default: "has-text-danger"
  },
  error: {
    type: Boolean,
    default: false
  },
  error_message: {
    type: String,
    default: "An error occurred"
  },
  dropdown_direction: {
    type: String,
    default: "down" // Alternative values: "up", "left", "right"
  },
  loading_message: {
    type: String,
    default: "Loading..."
  },
  loading_icon_class: {
    type: String,
    default: "fas fa-circle-notch"
  },
  loading_timeout_ms: {
    type: Number,
    default: 0 // 5 seconds
  },
  dropdown_content: {
    type: Object as () => {
      title: string|null;
      buttons_title: string|null;
      content: Array<{
        text: string;
        action: () => void;
        icon?: string;
        classes?: Array<string>;
        button?: boolean;
        button_text?: string;
        button_classes?: Array<string>;
        disabled?: boolean;
        v_centered?: boolean;
      }>;
      buttons: Array<{
        text: string;
        action: () => void;
        icon?: string;
        classes?: Array<string>;
        button_text?: string;
        button_classes?: Array<string>;
        disabled?: boolean;
        v_centered?: boolean;
      }>;
    },
    default: () => ({
      title: null,
      content: [
        /**
        { text: "Item #1", action: () => {}, icon: "fas fa-circle-notch", class: "has-text-info" },
        { text: "Item #2", action: () => {}, icon: "fas fa-circle-notch", class: "has-text-info" },
        { text: "Item #3", action: () => {}, icon: "fas fa-circle-notch", class: "has-text-info" }
         */
      ],
      buttons_title: null,
      buttons: [
        /**
        { text: "Example button #1", action: () => {}, icon: "fas fa-circle-notch", class: ["has-text-info", "is-small"], button_text: "Button #1", disabled: false },
        { text: "Example button #2", action: () => {}, icon: "fas fa-circle-notch", class: "has-text-info" },
        { text: "Example button #3", action: () => {}, icon: "fas fa-circle-notch", class: "has-text-info" }
         */
      ]
    })
  }
});

const emits = defineEmits(['onClick', 'onHover', 'onLeave', 'onScroll', 'onCopyToClipboard', 'onLoadingTimeout']);

const is_currently_hovered = ref(false);

const onClick = () => {
  emits('onClick');
};
const onHover = () => {
  is_currently_hovered.value = true;
  emits('onHover');
};
const onLeave = () => {
  is_currently_hovered.value = false;
  emits('onLeave');
};
const onScroll = () => {
  emits('onScroll');
};
const onLoadingTimeout = () => {
  // Check if the element is still loading
  if (props.is_loading) {
    console.warn('Loading timeout reached, but the element is still loading.');
    // If it is still loading, emit the loading timeout event
    emits('onLoadingTimeout');
  }
}
const copyToClipboard = (text) => {
  navigator.clipboard.writeText(text).then(() => {
    emits('onCopyToClipboard', text);
  }).catch(err => {
    console.error('Failed to copy: ', err);
  });
};

// Watch for scrolling
watch(() => props.is_loading, (newValue) => {
  if (newValue) {
    window.addEventListener('scroll', onScroll);
  } else {
    window.removeEventListener('scroll', onScroll);
  }
});

// Watch for loading timeout
watch(() => props.loading_timeout_ms, (newValue) => {
  if (newValue > 0) {
    setTimeout(() => {
      onLoadingTimeout();
    }, newValue);
  }
});

// Watch for loading state
watch(() => props.is_loading, (newValue) => {
  if (newValue) {
    // If loading, set a timeout to emit the loading timeout event
    if (props.loading_timeout_ms > 0) {
      setTimeout(() => {
        onLoadingTimeout();
      }, props.loading_timeout_ms);
    }
  }
});

// Start the loading timeout when the component is mounted
onMounted(() => {
  if (props.is_loading && props.loading_timeout_ms > 0) {
    setTimeout(() => {
      onLoadingTimeout();
    }, props.loading_timeout_ms);
  }
});

const label_shortened = computed(() => {
  if (props.label && props.label.text && props.label.max_length) {
    return props.label.text.length > props.label.max_length ? props.label.text.substring(0, props.label.max_length) + '...' : props.label.text;
  }
  return props.label.text;
});
</script>

<template>
  <div class="color-indicator" @click="onClick" @mouseover="onHover" @mouseleave="onLeave">
    <span class="icon-text is-flex-wrap-nowrap">
      <span class="icon" v-show="visibility.icon">
        <!-- Loading -->
        <template v-if="is_loading">
          <i class="fas fa-circle-notch fa-spin"></i>
        </template>
        <!-- Error state -->
        <template v-else-if="error">
          <i :class="[error_icon_class, error_class]"></i>
        </template>
        <!-- Not loading and not hovered -->
        <template v-else-if="!is_loading && !is_currently_hovered">
          <i :class="[icon_class, color_class]"></i>
        </template>
        <!-- Not loading and hovered -->
        <template v-else-if="!is_loading && is_currently_hovered">
          <i :class="[icon_class, color_class]"></i>
        </template>
        <!-- Loading and hovered -->
        <template v-else-if="is_loading && is_currently_hovered">
          <i class="fas fa-circle-notch fa-spin"></i>
        </template>
        <!-- Not loading and hovered -->
        <template v-else-if="!is_loading && is_currently_hovered">
          <i :class="[icon_class, color_class]"></i>
        </template>
        <!-- Not loading and not hovered -->
        <template v-else-if="!is_loading && !is_currently_hovered">
          <i :class="[icon_class, color_class]"></i>
        </template>
      </span>
      <!-- Label -->
      <span v-if="label && label.text" :class="[...label.classes]">
        {{ label_shortened }}
      </span>
    </span>
    <!-- Dropdown menu -->
    <div class="dropdown" :class="{ 'is-active': is_currently_hovered, 'is-up': dropdown_direction === 'up', 'is-left': dropdown_direction === 'left', 'is-right': dropdown_direction === 'right' }" v-if="props.visibility.dropdown">
      <div class="dropdown-menu">
        <div class="dropdown-content" v-if="is_currently_hovered">
          <!-- Error message, with copy button -->
          <template v-if="error">
            <div class="dropdown-item has-text-danger">
              <span>
                <span class="is-pulled-right">
                  <button class="button is-small is-light" @click="() => { copyToClipboard(error_message) }">
                    <i class="fas fa-copy"></i>
                  </button>
                </span>
                <span class="has-text-left">
                  <strong>Error:</strong>
                  <br />
                  {{ error_message }}
                </span>
              </span>
            </div>
          </template>
          <!-- Loading message -->
          <template v-else-if="is_loading">
            <div class="dropdown-item has-text-info">
              <strong>Loading...</strong>
            </div>
          </template>
          <!-- Normal state -->
          <template v-else>
            <!-- Dropdown content -->
            <template v-if="dropdown_content && dropdown_content.content">
              <!-- Dropdown label -->
              <template v-if="dropdown_content.title">
                <div class="dropdown-item has-text-info">
                  <strong>{{ dropdown_content.title }}</strong>
                </div>
                <!-- Divider -->
                <hr class="dropdown-divider" v-if="!props.is_narrow">
              </template>
                <template v-for="(item, index) in dropdown_content.content" :key="index">
                  <!-- Add divider if not the first item -->
                  <hr class="dropdown-divider" v-if="index > 0 && !props.is_narrow" />
                  <!-- Dropdown item -->
                  <div class="dropdown-item">
                    <div class="columns is-mobile" :class="{ 'is-vcentered': item.v_centered }">
                      <!-- Optional text -->
                      <div class="column is-auto-fill">
                        <span class="is-pulled-left">
                          {{ item.text }}
                        </span>
                      </div>
                      <!-- Optional button -->
                      <div class="column is-auto-fill" v-if="item.button">
                        <span class="is-pulled-right">
                          <button class="button is-small is-light" @click="() => { item.action() }" v-bind:disabled="item.disabled" v-bind:class="item.button_classes">
                            <!-- Optional button icon -->
                            <span class="icon" v-if="item.icon"><i :class="[item.icon, (item.classes ? item.classes : [])]"></i></span>
                            <!-- Optional button text, breaks lines if too long -->
                            <span v-if="item.button_text" v-bind:class="{ 'ml-2': item.icon }">{{ item.button_text }}</span>
                          </button>
                        </span>
                      </div>
                    </div>
                  </div>
                </template>
            </template>
            <!-- Dropdown buttons -->
            <template v-if="dropdown_content && dropdown_content.buttons">
              <!-- Dropdown label -->
              <div class="dropdown-item has-text-info" v-if="dropdown_content.buttons_title">
                <strong>{{ dropdown_content.buttons_title }}</strong>
                <!-- Divider -->
                <hr class="dropdown-divider" />
              </div>
                <template v-for="(button, index) in dropdown_content.buttons" :key="index">
                  <div class="dropdown-item">
                    <span class="is-pulled-right">
                      <button class="button is-small is-light" @click="() => { button.action() }" v-bind:disabled="button.disabled" v-bind:class="button.button_classes">
                        <span class="icon"><i :class="[button.icon, (button.classes ? button.classes : [])]"></i></span>
                        <!-- Optional button text -->
                        <template v-if="button.button_text">
                          <span v-if="button.icon" v-bind:class="{ 'ml-2': button.icon }">{{ button.button_text }}</span>
                        </template>
                      </button>
                    </span>
                    <span class="has-text-left">
                      {{ button.text }}
                    </span>
                  </div>
                </template>
            </template>
            <!-- If there's neither content nor buttons, show a message -->
            <template v-if="(!dropdown_content || !dropdown_content.content || dropdown_content.content.length === 0) && (!dropdown_content.buttons || dropdown_content.buttons.length === 0)">
              <div class="dropdown-item has-text-info">
                <strong>No content available</strong>
              </div>
            </template>
          </template>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
.no-underline-text {
  text-decoration: none !important;
}
</style>