<script setup>
import { useNamespace, useLocale } from "@yh-ui/hooks";
import { ref, computed, nextTick, watch } from "vue";
import { aiSenderProps, aiSenderEmits } from "./ai-sender";
import { YhButton } from "../../button";
import { YhIcon } from "../../icon";
import { YhImage } from "../../image";
import { YhAiMention } from "../../ai-mention";
import { useComponentTheme } from "@yh-ui/theme";
defineOptions({
  name: "YhAiSender"
});
const props = defineProps(aiSenderProps);
const emit = defineEmits(aiSenderEmits);
const ns = useNamespace("ai-sender");
const { t } = useLocale();
const { themeStyle } = useComponentTheme(
  "ai-sender",
  computed(() => props.themeOverrides)
);
const textareaRef = ref(null);
const localValue = ref(props.modelValue ?? "");
const isFocused = ref(false);
const commandPanelRef = ref();
const isDragging = ref(false);
const showCommands = ref(false);
const commandSearch = ref("");
const selectedCommandIndex = ref(0);
const handleDragEnter = (e) => {
  if (props.disabled || props.loading) return;
  e.preventDefault();
  isDragging.value = true;
};
const handleDragOver = (e) => {
  if (props.disabled || props.loading) return;
  e.preventDefault();
  isDragging.value = true;
};
const handleDragLeave = (e) => {
  e.preventDefault();
  const rect = e.currentTarget.getBoundingClientRect();
  if (e.clientX <= rect.left || e.clientX >= rect.right || e.clientY <= rect.top || e.clientY >= rect.bottom) {
    isDragging.value = false;
  }
};
const handleDrop = (e) => {
  if (props.disabled || props.loading) return;
  e.preventDefault();
  isDragging.value = false;
  const files = e.dataTransfer?.files;
  if (files && files.length > 0) {
    handleFiles(Array.from(files));
  }
};
const handleFiles = (files) => {
  emit("upload", files);
};
const handleRemoveAttachment = (attachment) => {
  emit("remove-attachment", attachment);
};
watch(
  () => props.modelValue,
  (val) => {
    localValue.value = val;
  }
);
const innerValue = computed({
  get: () => localValue.value,
  set: (val) => {
    if (localValue.value !== val) {
      localValue.value = val;
      emit("update:modelValue", val);
      emit("change", val);
    }
  }
});
const filteredCommands = computed(() => {
  if (!commandSearch.value) return props.commands;
  const search = commandSearch.value.toLowerCase();
  return props.commands.filter(
    (cmd) => cmd.key.toLowerCase().includes(search) || cmd.label.toLowerCase().includes(search)
  );
});
const autoResize = () => {
  const el = textareaRef.value?.getRef();
  if (!el) return;
  el.style.height = "auto";
  el.style.height = `${el.scrollHeight}px`;
};
const handleInput = (val) => {
  innerValue.value = val;
  const el = textareaRef.value?.getRef();
  if (!el) return;
  const cursorPosition = el.selectionStart || 0;
  const textBeforeCursor = val.slice(0, cursorPosition);
  const lastSlashIndex = textBeforeCursor.lastIndexOf("/");
  if (lastSlashIndex !== -1) {
    const textAfterSlash = textBeforeCursor.slice(lastSlashIndex + 1);
    if (lastSlashIndex === 0 || textBeforeCursor[lastSlashIndex - 1] === " " || textBeforeCursor[lastSlashIndex - 1] === "\n") {
      if (!textAfterSlash.includes(" ")) {
        showCommands.value = true;
        commandSearch.value = textAfterSlash;
        selectedCommandIndex.value = 0;
      } else {
        showCommands.value = false;
      }
    } else {
      showCommands.value = false;
    }
  } else {
    showCommands.value = false;
  }
  nextTick(autoResize);
};
const handleSelectCommand = (command) => {
  const val = innerValue.value;
  const el = textareaRef.value?.getRef();
  const cursorPosition = el?.selectionStart || 0;
  const textBeforeCursor = val.slice(0, cursorPosition);
  const lastSlashIndex = textBeforeCursor.lastIndexOf("/");
  const textAfterCursor = val.slice(cursorPosition);
  const replacement = command.prompt || `/${command.key} `;
  innerValue.value = textBeforeCursor.slice(0, lastSlashIndex) + replacement + textAfterCursor;
  showCommands.value = false;
  emit("command", command);
  nextTick(() => {
    textareaRef.value?.focus();
    autoResize();
  });
};
const handleKeyDown = (e) => {
  if (showCommands.value && filteredCommands.value.length > 0) {
    if (e.key === "ArrowDown") {
      e.preventDefault();
      selectedCommandIndex.value = (selectedCommandIndex.value + 1) % filteredCommands.value.length;
    } else if (e.key === "ArrowUp") {
      e.preventDefault();
      selectedCommandIndex.value = (selectedCommandIndex.value - 1 + filteredCommands.value.length) % filteredCommands.value.length;
    } else if (e.key === "Enter" || e.key === "Tab") {
      e.preventDefault();
      handleSelectCommand(filteredCommands.value[selectedCommandIndex.value]);
    } else if (e.key === "Escape") {
      showCommands.value = false;
    }
    return;
  }
  if (e.key === "Enter" && !e.shiftKey) {
    if (!innerValue.value?.trim() || props.loading || props.disabled) {
      e.preventDefault();
    } else {
      e.preventDefault();
      handleSend();
    }
  }
};
const handleSend = () => {
  if (!innerValue.value?.trim() || props.loading || props.disabled) return;
  emit("send", innerValue.value);
  innerValue.value = "";
  nextTick(() => {
    const el = textareaRef.value?.getRef();
    if (el) {
      el.style.height = "auto";
    }
  });
};
const handleClear = () => {
  innerValue.value = "";
  emit("clear");
  nextTick(autoResize);
};
const handleBlur = (e) => {
  isFocused.value = false;
  setTimeout(() => {
    showCommands.value = false;
  }, 200);
  emit("blur", e);
};
const handleFocus = (e) => {
  isFocused.value = true;
  emit("focus", e);
};
</script>

<template>
  <div
    :class="[ns.b(), ns.is('disabled', disabled), ns.is('loading', loading), ns.is('focused', isFocused)]"
    :style="themeStyle"
    @dragenter="handleDragEnter"
    @dragover="handleDragOver"
    @dragleave="handleDragLeave"
    @drop="handleDrop"
  >
    <!-- Drag Overlay -->
    <Transition name="yh-fade-in">
      <div v-if="isDragging" :class="ns.e('drag-overlay')">
        <div :class="ns.e('drag-message')">
          <YhIcon name="upload" />
          <span>{{ t('ai.sender.dragTip') }}</span>
        </div>
      </div>
    </Transition>
    <!-- Slash Commands Panel -->
    <Transition name="yh-zoom-in-bottom">
      <div
        v-if="showCommands && filteredCommands.length > 0"
        ref="commandPanelRef"
        :class="ns.e('command-panel')"
      >
        <div
          v-for="(cmd, index) in filteredCommands"
          :key="cmd.key"
          :class="[ns.e('command-item'), ns.is('active', index === selectedCommandIndex)]"
          @click="handleSelectCommand(cmd)"
        >
          <div :class="ns.e('command-icon')">
            <YhIcon :name="cmd.icon || 'sparkles'" />
          </div>
          <div :class="ns.e('command-info')">
            <div :class="ns.e('command-label')">/{{ cmd.key }}</div>
            <div v-if="cmd.description" :class="ns.e('command-desc')">{{ cmd.description }}</div>
          </div>
        </div>
      </div>
    </Transition>

    <div :class="ns.e('input-wrapper')">
      <div v-if="$slots.prefix" :class="ns.e('prefix')">
        <slot name="prefix"></slot>
      </div>

      <!-- Attachments Area -->
      <div v-if="attachments && attachments.length > 0" :class="ns.e('attachments')">
        <div
          v-for="file in attachments"
          :key="file.id"
          :class="[ns.e('attachment-item'), ns.is(file.status || 'success')]"
        >
          <div :class="ns.e('attachment-preview')">
            <template v-if="file.type.startsWith('image/')">
              <YhImage
                :src="file.url"
                :alt="file.name"
                :preview-src-list="file.url ? [file.url] : []"
                preview-teleported
                fit="cover"
              />
            </template>
            <YhIcon v-else :name="'document'" />
          </div>
          <div :class="ns.e('attachment-info')">
            <div :class="ns.e('attachment-name')" :title="file.name">{{ file.name }}</div>
            <div v-if="file.status === 'uploading'" :class="ns.e('attachment-progress')">
              <div
                :class="ns.e('progress-bar')"
                :style="{
  width: (file.progress || 0) + '%'
}"
              ></div>
            </div>
          </div>
          <button :class="ns.e('attachment-remove')" @click="handleRemoveAttachment(file)">
            <YhIcon name="close" />
          </button>
        </div>
      </div>

      <div :class="ns.e('textarea-container')">
        <YhAiMention
          ref="textareaRef"
          v-model="innerValue"
          type="textarea"
          :class="ns.e('textarea')"
          :placeholder="placeholder ?? t('ai.sender.placeholder')"
          :disabled="disabled || loading"
          :max-length="maxLength"
          :rows="1"
          :options="mentionOptions"
          :trigger="['@', '#']"
          @focus="handleFocus"
          @blur="handleBlur"
          @input="handleInput"
          @keydown="handleKeyDown"
        />
      </div>

      <div :class="ns.e('suffix')">
        <span v-if="showWordLimit && maxLength" :class="ns.e('word-limit')">
          {{ innerValue.length }} / {{ maxLength }}
        </span>
      </div>

      <div :class="ns.e('actions')">
        <slot name="actions"></slot>

        <YhButton
          v-if="clearable && innerValue.length > 0"
          :class="ns.e('clear-btn')"
          circle
          :aria-label="t('common.clear') || 'Clear input'"
          @click="handleClear"
          :disabled="loading"
        >
          <template #icon>
            <YhIcon name="clean" />
          </template>
        </YhButton>

        <slot
          name="submit"
          :disabled="!innerValue?.trim() || disabled"
          :loading="loading"
          :submit="handleSend"
        >
          <YhButton
            :type="innerValue?.trim() && !disabled && !loading ? 'primary' : 'default'"
            :class="ns.e('send-btn')"
            :disabled="!innerValue?.trim() || disabled"
            :loading="loading"
            :aria-label="t('ai.sender.placeholder') || 'Send message'"
            @click="handleSend"
            circle
          >
            <template #icon>
              <YhIcon name="send-arrow" />
            </template>
          </YhButton>
        </slot>
      </div>
    </div>
  </div>
</template>

<style>
@charset "UTF-8";
/**
 * YH-UI Sass Variables
 * 原具体的 CSS 变量输出规则 (:root, html.dark 等) 已移至 root.scss，以防止各组件样式编译时产生重复的全局变量 CSS 冗余。
 */
.yh-ai-sender {
  --yh-ai-sender-bg: var(--yh-ai-sender-bg-color, var(--yh-bg-color-overlay));
  --yh-ai-sender-border-color: var(--yh-ai-sender-border-color, var(--yh-border-color));
  --yh-ai-sender-focus-border-color: var(
    --yh-ai-sender-focus-border-color,
    var(--yh-color-primary)
  );
  --yh-ai-sender-border-radius: var(--yh-ai-sender-border-radius, 16px);
  --yh-ai-sender-shadow: var(--yh-ai-sender-box-shadow, 0 4px 16px rgba(0, 0, 0, 0.08));
  --yh-ai-sender-focus-shadow: var(
    --yh-ai-sender-focus-box-shadow,
    0 6px 20px rgba(var(--yh-color-primary-rgb), 0.15)
  );
  width: 100%;
  position: relative;
  border-radius: var(--yh-ai-sender-border-radius);
  background-color: var(--yh-ai-sender-bg);
  box-shadow: var(--yh-ai-sender-shadow);
  border: 1px solid var(--yh-ai-sender-border-color);
  transition: all 0.3s ease;
}
.yh-ai-sender.is-focused {
  border-color: var(--yh-ai-sender-focus-border-color);
  box-shadow: var(--yh-ai-sender-focus-shadow);
}

.yh-ai-sender.is-disabled {
  background-color: var(--yh-fill-color-light);
  opacity: 0.7;
  cursor: not-allowed;
}

.yh-ai-sender__input-wrapper {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  padding: 12px 16px;
  gap: 8px;
  position: relative;
}
.yh-ai-sender__attachments {
  width: 100%;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 8px;
}

.yh-ai-sender__attachment-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  background: var(--yh-fill-color-light);
  border: 1px solid var(--yh-border-color-lighter);
  border-radius: 8px;
  max-width: 180px;
  transition: all 0.2s;
}
.yh-ai-sender__attachment-item.is-uploading {
  opacity: 0.8;
}

.yh-ai-sender__attachment-item:hover {
  background: var(--yh-fill-color-lighter);
}
.yh-ai-sender__attachment-item:hover .yh-ai-sender__attachment-remove {
  opacity: 1;
}

.yh-ai-sender__attachment-preview {
  width: 32px;
  height: 32px;
  border-radius: 4px;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--yh-bg-color);
  flex-shrink: 0;
}
.yh-ai-sender__attachment-preview img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.yh-ai-sender__attachment-preview .yh-icon {
  font-size: 18px;
  color: var(--yh-text-color-secondary);
}

.yh-ai-sender__attachment-info {
  flex: 1;
  min-width: 0;
}

.yh-ai-sender__attachment-name {
  font-size: 12px;
  color: var(--yh-text-color-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.yh-ai-sender__attachment-progress {
  width: 100%;
  height: 2px;
  background: var(--yh-border-color-lighter);
  border-radius: 1px;
  margin-top: 4px;
  overflow: hidden;
}

.yh-ai-sender__progress-bar {
  height: 100%;
  background: var(--yh-color-primary);
  transition: width 0.3s;
}

.yh-ai-sender__attachment-remove {
  position: absolute;
  top: -8px;
  right: -8px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--yh-text-color-regular);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  cursor: pointer;
  opacity: 0;
  transition: all 0.2s;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.yh-ai-sender__attachment-remove .yh-icon {
  font-size: 10px;
}
.yh-ai-sender__attachment-remove:hover {
  background: var(--yh-color-danger);
  transform: scale(1.1);
}

.yh-ai-sender__prefix {
  display: flex;
  align-items: center;
  padding-bottom: 4px;
}

.yh-ai-sender__textarea-container {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.yh-ai-sender__textarea {
  width: 100%;
  min-height: 24px;
  max-height: 200px;
  line-height: 1.5;
  border: none;
  outline: none;
  background: transparent;
  resize: none;
  color: var(--yh-text-color-primary);
  font-family: inherit;
  font-size: var(--yh-font-size-base);
}
.yh-ai-sender__textarea::placeholder {
  color: var(--yh-text-color-placeholder);
}
.yh-ai-sender__textarea:disabled {
  cursor: not-allowed;
}

.yh-ai-sender__suffix {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: 4px;
  padding-bottom: 4px;
}

.yh-ai-sender__word-limit {
  font-size: 12px;
  color: var(--yh-text-color-placeholder);
}

.yh-ai-sender__clear-icon {
  color: var(--yh-text-color-placeholder);
  cursor: pointer;
  transition: color 0.2s;
  font-size: 16px;
}
.yh-ai-sender__clear-icon:hover {
  color: var(--yh-text-color-regular);
}

.yh-ai-sender__actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 8px;
  padding-bottom: 2px;
}

.yh-ai-sender__send-btn {
  transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.yh-ai-sender__send-btn:not(:disabled):hover {
  transform: scale(1.05);
}
.yh-ai-sender__send-btn:active {
  transform: scale(0.95);
}

.yh-ai-sender__command-panel {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 0;
  right: 0;
  background: var(--yh-bg-color-overlay);
  border: 1px solid var(--yh-border-color-lighter);
  border-radius: 12px;
  box-shadow: var(--yh-shadow-light);
  padding: 6px;
  z-index: 1000;
  max-height: 240px;
  overflow-y: auto;
  backdrop-filter: blur(10px);
  animation: yh-fade-in-up 0.3s cubic-bezier(0.23, 1, 0.32, 1);
}

.yh-ai-sender__command-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 12px;
  border-radius: 8px;
  cursor: pointer;
  transition: all 0.2s;
}
.yh-ai-sender__command-item.is-active {
  background: var(--yh-fill-color-light);
}
.yh-ai-sender__command-item.is-active .yh-ai-sender__command-label {
  color: var(--yh-color-primary);
}

.yh-ai-sender__command-item:hover {
  background: var(--yh-fill-color-lighter);
}

.yh-ai-sender__command-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  background: var(--yh-fill-color-light);
  border-radius: 6px;
  color: var(--yh-text-color-secondary);
  font-size: 16px;
}

.yh-ai-sender__command-info {
  flex: 1;
  min-width: 0;
}

.yh-ai-sender__command-label {
  font-size: 14px;
  font-weight: 600;
  color: var(--yh-text-color-primary);
  line-height: 1.4;
}

.yh-ai-sender__command-desc {
  font-size: 12px;
  color: var(--yh-text-color-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.2;
  margin-top: 2px;
}

@keyframes yh-fade-in-up {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
.yh-ai-sender__drag-overlay {
  position: absolute;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(var(--yh-color-primary-rgb), 0.1);
  backdrop-filter: blur(4px);
  border: 2px dashed var(--yh-color-primary);
  border-radius: 12px;
  transition: all 0.3s ease;
  pointer-events: none;
}

.yh-ai-sender__drag-message {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  color: var(--yh-color-primary);
  font-size: 14px;
  font-weight: 500;
}
.yh-ai-sender__drag-message .yh-icon {
  font-size: 32px;
}

@keyframes yh-sender-fade-in {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
</style>
