<script setup lang="ts">
import type { Attachment, ChatMessage, VoiceMessage } from './types';

/**
 * ChatBox 通用聊天组件 - ChatGPT 风格
 *
 * 适配场景：
 * - 工作流对话
 * - 智能体对话
 * - AI 对话
 */
import { computed, nextTick, ref, watch } from 'vue';

import { ChevronDown, ChevronUp, Trash2 } from '@vben/icons';
import { useUserStore } from '@vben/stores';

import { ElScrollbar } from 'element-plus';

import AiWorkingAnimation from '#/components/ai-loading/AiWorkingAnimation.vue';
import { getFileUrl } from '#/composables/useFileUrl';

import InputArea from './InputArea.vue';
import MessageBubble from './MessageBubble.vue';

const props = withDefaults(
  defineProps<{
    acceptFileTypes?: string;
    assistantAvatar?: string;
    assistantName?: string;
    disabled?: boolean;
    emptyText?: string;
    enableAttachment?: boolean;
    enableFeedback?: boolean;
    enableImage?: boolean;
    enableRegenerate?: boolean;
    enableVoice?: boolean;
    loading?: boolean;
    maxAttachmentSize?: number;
    messages: ChatMessage[];
    placeholder?: string;
    showAvatar?: boolean;
    showClearButton?: boolean;
    showReasoningSteps?: boolean;
    streamingContent?: string;
    userAvatar?: string;
    // 欢迎配置
    welcomeConfig?: {
      description?: string;
      suggestions?: string[];
      title?: string;
    };
  }>(),
  {
    loading: false,
    showAvatar: true,
    placeholder: '输入消息...',
    disabled: false,
    enableAttachment: false,
    enableImage: false,
    enableVoice: false,
    enableFeedback: false,
    enableRegenerate: false,
    showReasoningSteps: false,
    maxAttachmentSize: 10,
    acceptFileTypes: '.pdf,.doc,.docx,.txt,.md,.json,.csv,.xlsx,.ppt,.pptx',
    showClearButton: false,
    emptyText: '开始对话吧',
  },
);

const emit = defineEmits<{
  (e: 'send', message: string, attachments?: Attachment[]): void;
  (e: 'stop'): void;
  (e: 'regenerate', messageId: string): void;
  (e: 'feedback', messageId: string, feedback: 'dislike' | 'like'): void;
  (e: 'clear'): void;
  (e: 'upload', file: File): Promise<Attachment>;
  /** 对话流交互提交 */
  (e: 'interaction-submit', messageId: string, value: any): void;
  /** 对话流交互取消 */
  (e: 'interaction-cancel', messageId: string): void;
  /** 添加消息（内部使用，用于语音消息） */
  (e: 'add-message', message: ChatMessage): void;
  /** 更新消息（内部使用，用于语音识别完成） */
  (e: 'update-message', messageId: string, updates: Partial<ChatMessage>): void;
}>();

// 滚动容器 - ElScrollbar 实例
const scrollbarRef = ref<InstanceType<typeof ElScrollbar> | null>(null);

// 用户头像预加载（避免每条消息重复加载）
const userStore = useUserStore();
const currentUser = computed(() => userStore.userInfo);
const cachedUserAvatarUrl = ref<string | undefined>(undefined);

// 预加载用户头像 URL
async function loadUserAvatarUrl() {
  if (currentUser.value?.avatar) {
    cachedUserAvatarUrl.value = await getFileUrl(currentUser.value.avatar);
  }
}

// 监听用户信息变化，重新加载头像
watch(
  () => currentUser.value?.avatar,
  () => {
    loadUserAvatarUrl();
  },
  { immediate: true },
);

// 滚动到底部
const scrollToBottom = () => {
  nextTick(() => {
    if (scrollbarRef.value) {
      const wrapElement = scrollbarRef.value.wrapRef;
      if (wrapElement) {
        scrollbarRef.value.setScrollTop(wrapElement.scrollHeight);
      }
    }
  });
};

// 监听消息变化，自动滚动
watch(
  () => props.messages.length,
  () => {
    scrollToBottom();
  },
);

// 监听流式内容变化，自动滚动
watch(
  () => props.streamingContent,
  () => {
    scrollToBottom();
  },
);

// 处理发送
const handleSend = (message: string, attachments?: Attachment[]) => {
  emit('send', message, attachments);
  scrollToBottom();
};

// 处理停止
const handleStop = () => {
  emit('stop');
};

// 处理重新生成
const handleRegenerate = (messageId: string) => {
  emit('regenerate', messageId);
};

// 处理反馈
const handleFeedback = (messageId: string, feedback: 'dislike' | 'like') => {
  emit('feedback', messageId, feedback);
};

// 处理清空
const handleClear = () => {
  emit('clear');
};

// 处理复制
const handleCopy = () => {
  // 复制成功提示由 MessageBubble 处理
};

// 处理语音消息发送（内部处理，添加语音消息到列表）
const handleSendVoice = (voice: VoiceMessage & { voiceId?: string }) => {
  const voiceId = voice.voiceId || `voice-${Date.now()}`;

  // 创建用户语音消息
  const userMsg: ChatMessage = {
    id: voiceId,
    role: 'user',
    content: '', // 语音消息内容为空，通过 voice 字段显示
    timestamp: new Date(),
    voice,
  };

  // 通知父组件添加消息
  emit('add-message', userMsg);
  scrollToBottom();
};

// 处理语音识别完成（内部处理，更新消息并触发 send）
const handleVoiceTranscribed = (voiceId: string, text: string) => {
  // 更新语音消息状态
  emit('update-message', voiceId, {
    content: text,
    voice: {
      transcribeStatus: 'completed',
      transcribedText: text,
    } as any,
  });

  // 识别成功后，触发 send 事件（让父组件处理发送逻辑）
  if (text && !text.startsWith('[')) {
    emit('send', text);
  }
};

// 推荐问题展开状态
const suggestionsExpanded = ref(false);
const MAX_VISIBLE_SUGGESTIONS = 6;

// 显示的推荐问题
const visibleSuggestions = computed(() => {
  const suggestions = props.welcomeConfig?.suggestions || [];
  if (
    suggestionsExpanded.value ||
    suggestions.length <= MAX_VISIBLE_SUGGESTIONS
  ) {
    return suggestions;
  }
  return suggestions.slice(0, MAX_VISIBLE_SUGGESTIONS);
});

// 是否有更多推荐问题
const hasMoreSuggestions = computed(() => {
  const suggestions = props.welcomeConfig?.suggestions || [];
  return suggestions.length > MAX_VISIBLE_SUGGESTIONS;
});

// 点击建议问题
const handleSuggestionClick = (suggestion: string) => {
  emit('send', suggestion);
};

// 切换推荐问题展开状态
const toggleSuggestionsExpand = () => {
  suggestionsExpanded.value = !suggestionsExpanded.value;
};

// 暴露方法
defineExpose({
  scrollToBottom,
});
</script>

<template>
  <div class="chatbox" :class="{ 'chatbox-empty': messages.length === 0 }">
    <!-- 内容区域（欢迎页或消息列表） -->
    <div v-if="messages.length === 0" class="chatbox-content">
      <div class="chatbox-center">
        <!-- AI 工作动画 -->
        <AiWorkingAnimation
          :title="welcomeConfig?.title || ''"
          :subtitle="welcomeConfig?.description || emptyText || '开始对话吧'"
          :show-progress="false"
          :show-steps="false"
          :show-background="false"
          class="h-full min-h-[400px] flex-1"
        >
          <!-- 建议问题 -->
          <div
            v-if="welcomeConfig?.suggestions?.length"
            class="welcome-suggestions"
          >
            <div class="suggestions-grid">
              <button
                v-for="(suggestion, idx) in visibleSuggestions"
                :key="idx"
                class="suggestion-btn"
                @click="handleSuggestionClick(suggestion)"
              >
                <span>{{ suggestion }}</span>
              </button>
            </div>
            <!-- 展开/收起按钮 -->
            <button
              v-if="hasMoreSuggestions"
              class="expand-btn"
              @click="toggleSuggestionsExpand"
            >
              <span>{{
                suggestionsExpanded
                  ? '收起'
                  : `查看更多 (${welcomeConfig.suggestions.length - MAX_VISIBLE_SUGGESTIONS})`
              }}</span>
              <component
                :is="suggestionsExpanded ? ChevronUp : ChevronDown"
                class="size-4"
              />
            </button>
          </div>
        </AiWorkingAnimation>
      </div>
    </div>

    <!-- 有消息时：消息列表 -->
    <template v-else>
      <!-- 消息列表 -->
      <ElScrollbar ref="scrollbarRef" class="chatbox-messages">
        <div class="messages-container">
          <MessageBubble
            v-for="(message, index) in messages"
            :key="message.id"
            :message="message"
            :show-avatar="showAvatar"
            :user-avatar="userAvatar"
            :cached-user-avatar-url="cachedUserAvatarUrl"
            :current-user="currentUser"
            :assistant-avatar="assistantAvatar"
            :assistant-name="assistantName"
            :enable-feedback="enableFeedback"
            :enable-regenerate="enableRegenerate"
            :show-reasoning-steps="showReasoningSteps"
            :is-last="index === messages.length - 1"
            @regenerate="handleRegenerate"
            @feedback="handleFeedback"
            @copy="handleCopy"
            @interaction-submit="
              (msgId, value) => $emit('interaction-submit', msgId, value)
            "
            @interaction-cancel="(msgId) => $emit('interaction-cancel', msgId)"
          />
        </div>
      </ElScrollbar>

      <!-- 清空按钮 -->
      <button
        v-if="showClearButton && messages.length > 0"
        class="clear-btn"
        title="清空对话"
        @click="handleClear"
      >
        <Trash2 class="size-4" />
      </button>
    </template>

    <!-- 输入区域（始终固定在底部） -->
    <div class="input-wrapper-bottom">
      <InputArea
        :loading="loading"
        :disabled="disabled"
        :placeholder="placeholder"
        :enable-attachment="enableAttachment"
        :enable-image="enableImage"
        :enable-voice="enableVoice"
        :max-attachment-size="maxAttachmentSize"
        :accept-file-types="acceptFileTypes"
        @send="handleSend"
        @stop="handleStop"
        @send-voice="handleSendVoice"
        @voice-transcribed="handleVoiceTranscribed"
      />
    </div>
  </div>
</template>

<style scoped>
.chatbox {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--el-bg-color);
  border-radius: 8px;
  /* border: 1px solid var(--el-border-color-lighter); */
  overflow: hidden;
  position: relative;
}

/* 内容区域（欢迎页或消息列表） */
.chatbox-content {
  flex: 1;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}

.chatbox-messages {
  flex: 1;
  padding: 16px;
}

.chatbox-messages :deep(.el-scrollbar__wrap) {
  overflow-x: hidden;
}

.chatbox-messages :deep(.el-scrollbar__view) {
  height: 100%;
}

/* 初始状态居中布局 */
.chatbox-center {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  flex: 1;
  padding: 20px;
  gap: 32px;
}

/* 输入框包装器 - 底部 */
.input-wrapper-bottom {
  width: 100%;
  max-width: 830px;
  margin: 0 auto;
  padding: 0 16px 16px;
}

/* 欢迎页 */
.chatbox-welcome {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.welcome-icon {
  width: 72px;
  height: 72px;
  border-radius: 50%;
  background: var(--el-color-primary-light-9);
  color: var(--el-color-primary);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 20px;
}

.welcome-title {
  font-size: 20px;
  font-weight: 600;
  color: var(--el-text-color-primary);
  margin: 0 0 8px;
}

.welcome-desc {
  font-size: 14px;
  color: var(--el-text-color-secondary);
  margin: 0;
  max-width: 400px;
}

.welcome-suggestions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  width: calc(100% - 0px);
  max-width: 800px;
}

.suggestions-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  width: 100%;
}

@media (max-width: 640px) {
  .suggestions-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 480px) {
  .suggestions-grid {
    grid-template-columns: 1fr;
  }
}

.suggestion-btn {
  padding: 8px 16px;
  border: 1px solid var(--el-border-color);
  border-radius: 10px;
  background: var(--el-bg-color);
  color: var(--el-text-color-regular);
  font-size: 13px;
  cursor: pointer;
  transition: all 0.2s;
  text-align: center;
  line-height: 1.5;
  min-height: 48px;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.suggestion-btn span {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-overflow: ellipsis;
  word-break: break-all;
}

.suggestion-btn:hover {
  border-color: var(--el-color-primary);
  color: var(--el-color-primary);
  background: var(--el-color-primary-light-9);
}

.expand-btn {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 6px 12px;
  border: none;
  border-radius: 16px;
  background: var(--el-fill-color-light);
  color: var(--el-text-color-secondary);
  font-size: 12px;
  cursor: pointer;
  transition: all 0.2s;
}

.expand-btn:hover {
  background: var(--el-fill-color);
  color: var(--el-text-color-primary);
}

/* 消息容器 */
.messages-container {
  max-width: 800px;
  margin: 0 auto;
}

/* 清空按钮 */
.clear-btn {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 32px;
  height: 32px;
  border: none;
  border-radius: 8px;
  background: var(--el-fill-color);
  color: var(--el-text-color-secondary);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s;
  opacity: 0.6;
}

.clear-btn:hover {
  opacity: 1;
  background: var(--el-fill-color-dark);
  color: var(--el-text-color-primary);
}
</style>
