<template>
  <div
    class="checkbox"
    :class="{
      'checkbox--disabled': disabled,
      'checkbox--has-error': error,
      'checkbox--large-icon': iconSize === 'large',
      'checkbox--wrap': wrap,
      'has-label': label,
      [`label-${labelPosition}`]: label,
      [`label-align-${labelAlign}`]: label,
      [`checkbox--${presentation}`]: presentation,
    }"
    :style="[
      { width: width || '100%' },
      labelStyle,
      {
        '--checkbox-color': error ? 'var(--error-color)' : color,
        '--checkbox-hover-color': hoverColor ? hoverColor : 'var(--checkbox-color)',
        '--checkbox-active-color': activeColor ? activeColor : 'var(--checkbox-color)',
        '--checkbox-disabled-color': disabledColor,
        '--checkbox-background-color': backgroundColor,
        '--checkbox-border-radius': borderRadius,
        '--checkbox-padding': padding,
      },
    ]"
  >
    <label v-if="label" :for="id" class="label">
      {{ label }}
    </label>
    <div
      class="checkbox__options"
      :style="{
        'grid-template-columns': `repeat(${columns || 1}, 1fr)`,
        gap: presentation === 'minimal' ? '0' : '0.5rem',
      }"
    >
      <div
        v-for="option in options"
        :key="String(option.id)"
        class="checkbox__option"
        :class="{
          'checkbox__option--disabled': option.disabled || disabled,
          'checkbox__option--selected': isSelected(option),
          'checkbox__option--round': !multiple && options?.length > 1,
          'checkbox__option--has-label': option.label,
        }"
        @click.prevent="() => toggleOption(option)"
      >
        <div class="checkbox__icon">
          <font-awesome-icon
            v-if="isSelected(option)"
            :icon="multiple ? 'square-check' : 'circle-check'"
          />
          <font-awesome-icon v-else :icon="multiple ? 'square' : 'circle'" />
        </div>
        <div v-if="option.label" class="checkbox__label">{{ option.label }}</div>
      </div>
    </div>
    <span
      v-if="required && !showSaved && !showChanged && !error"
      class="status-indicator required-indicator"
      >required</span
    >
    <transition name="fade">
      <span v-if="showSaved && !error" class="status-indicator saved-indicator">saved</span>
    </transition>
    <transition name="fade">
      <span v-if="showChanged && !error" class="status-indicator changed-indicator">changed</span>
    </transition>
    <transition name="fade">
      <span v-if="error" class="status-indicator error-indicator" :data-error="error">error</span>
    </transition>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import type { CheckboxProps, CheckboxOption } from '../types/checkbox'

const props = withDefaults(defineProps<CheckboxProps>(), {
  multiple: false,
  wrap: false,
  disabled: false,
  options: () => [],
  width: '100%',
  color: 'var(--text-primary)',
  hoverColor: '',
  activeColor: '',
  disabledColor: 'var(--text-disabled)',
  backgroundColor: 'transparent',
  borderRadius: '0.375rem',
  padding: '0.25rem 0.5rem',
  icon: '',
  iconSize: 'normal',
  required: false,
  error: '',
  label: '',
  labelPosition: 'top',
  labelAlign: 'left',
  labelWidth: '',
  columns: 1,
  presentation: 'default',
})

const emit = defineEmits<{
  (e: 'update:modelValue', value: string | string[]): void
  (e: 'changed'): void
  (e: 'saved'): void
}>()

const id = ref<string>('')
const showSaved = ref(false)
const showChanged = ref(false)
const isChanged = ref(false)
const debounceTimer = ref<number | null>(null)
const changedTimer = ref<number | null>(null)

const isSelected = (option: CheckboxOption) => {
  if (Array.isArray(props.modelValue)) {
    return props.modelValue.includes(String(option.id))
  }
  return String(option.id) === String(props.modelValue)
}

const toggleOption = (option: CheckboxOption) => {
  if (option.disabled || props.disabled) return

  if (props.multiple) {
    const currentValue = Array.isArray(props.modelValue) ? props.modelValue : []
    const newValue = currentValue.includes(String(option.id))
      ? currentValue.filter((id) => id !== String(option.id))
      : [...currentValue, String(option.id)]
    emit('update:modelValue', newValue)
    debounceAutosave(newValue)
  } else {
    const newValue = String(option.id) === String(props.modelValue) ? '' : String(option.id)
    emit('update:modelValue', newValue)
    debounceAutosave(newValue)
  }
}

const handleAutosave = async (value: string | string[]) => {
  if (props.autosave) {
    try {
      await props.autosave(value)
      if (!props.error) {
        emit('saved')
        showSaved.value = true
        showChanged.value = false
        setTimeout(() => {
          showSaved.value = false
        }, 3000)
      }
    } catch (error) {
      console.error('Autosave failed:', error)
    }
  }
}

const debounceAutosave = (value: string | string[]) => {
  if (debounceTimer.value) {
    clearTimeout(debounceTimer.value)
  }
  if (changedTimer.value) {
    clearTimeout(changedTimer.value)
  }

  if (!props.error) {
    showChanged.value = true
  }

  changedTimer.value = window.setTimeout(() => {
    emit('changed')
    isChanged.value = true
  }, 500)

  debounceTimer.value = window.setTimeout(() => {
    handleAutosave(value)
  }, 1500)
}

onMounted(() => {
  id.value = `checkbox-${Math.random().toString(36).substring(2, 11)}`
})

const labelStyle = computed(() => {
  if (!props.label) return {}
  if (props.labelPosition === 'left' && props.labelWidth) {
    return {
      'grid-template-columns': `${props.labelWidth} 1fr`,
    }
  }
  return {}
})
</script>

<style scoped>
.checkbox {
  position: relative;
  width: var(--checkbox-width);
  font-family: Arial, sans-serif;
  cursor: pointer;
  user-select: none;
  outline: none;
  display: grid;
  gap: 0.5rem;

  .checkbox__options {
    display: grid;
    gap: 0.5rem;
  }

  &.checkbox--minimal .checkbox__options {
    gap: 0;
  }
}

.checkbox--disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.checkbox--has-error {
  border-color: var(--error-color);
}

.checkbox__option {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: var(--checkbox-padding);
  border: 1px solid var(--checkbox-color);
  border-radius: var(--checkbox-border-radius);
  background-color: var(--checkbox-background-color);
  color: var(--checkbox-color);
  transition: all 0.2s ease;
  min-width: 0;

  &:not(.checkbox__option--has-label) {
    max-width: 2.2rem;
  }
}

.checkbox--minimal .checkbox__option {
  border: none;
  border-radius: 0;
  padding: 0.25rem 0.5rem;
  margin: 0;
}

.checkbox__option:hover {
  border-color: var(--checkbox-hover-color);
  color: var(--checkbox-hover-color);
  background-color: rgba(from var(--checkbox-active-color) r g b / 0.2);
}

.checkbox__option--selected {
  border-color: var(--checkbox-active-color);
  color: var(--checkbox-active-color);
}

.checkbox__option--selected.checkbox__option--has-label {
  background-color: rgba(from var(--checkbox-active-color) r g b / 0.1);
}

.checkbox__option--disabled {
  opacity: 0.6;
  cursor: not-allowed;
  color: var(--checkbox-disabled-color);
}

.checkbox--minimal .checkbox__option--disabled {
  background-color: transparent;
}

.checkbox__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.2em;
  flex-shrink: 0;
}

.checkbox__label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.checkbox--wrap .checkbox__label {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}

.status-indicator {
  position: absolute;
  top: -1px;
  line-height: 1px;
  right: 0.5rem;
  font-size: 0.75rem;
  color: var(--text-muted);
  background-color: var(--checkbox-background-color);
  padding: 0 0.25rem;
}

.status-indicator.saved-indicator {
  color: var(--success-color);
}

.status-indicator.changed-indicator {
  color: var(--warning-color);
}

.status-indicator.error-indicator {
  color: var(--error-color);
}

.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.2s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

.checkbox.label-top {
  grid-template-rows: auto 1fr;
}

.checkbox.label-left {
  grid-template-columns: 30% 1fr;
  align-items: start;
  gap: 1rem;
}

.checkbox.label-left .label {
  padding-top: 0.25rem;
  width: 100%;
}

.label {
  font-weight: 500;
  color: var(--text-color);
  text-align: left;
}

.label-align-left .label {
  text-align: left;
}

.label-align-right .label {
  text-align: right;
}

.label-align-center .label {
  text-align: center;
}
</style>
