<script setup lang="ts">
import type { ImApi } from '#/api/core/im';

import { computed, nextTick, onMounted, onUnmounted, reactive, ref } from 'vue';

import { useUserStore } from '@vben/stores';

import {
  Avatar,
  Badge,
  Button,
  Form,
  FormItem,
  Input,
  message,
  Modal,
  Select,
  SelectOption,
  Spin,
} from 'ant-design-vue';

import { uploadFileApi } from '#/api/core/file-management';
import { fileRequestClient } from '#/api/request';
import { createGroupApi } from '#/api';
import { useImStore } from '#/store';

const InputSearch = Input.Search;

const userStore = useUserStore();
const imStore = useImStore();

const inputMessage = ref('');
const sending = ref(false);
const uploading = ref(false);
const showCreateGroup = ref(false);
const showGroupManage = ref(false);
const showEmojiPicker = ref(false);
const newGroupName = ref('');
const newGroupDesc = ref('');
const selectedMemberIds = ref<string[]>([]);
const memberSearchLoading = ref(false);
const messageListRef = ref<HTMLElement | null>(null);
const fileInputRef = ref<HTMLInputElement | null>(null);
const imageInputRef = ref<HTMLInputElement | null>(null);

const sidebarTab = ref<'contacts' | 'messages'>('messages');
const contactSearchQuery = ref('');
let contactSearchTimer: null | ReturnType<typeof setTimeout> = null;

const EMOJI_LIST = [
  '😀', '😂', '🤣', '😊', '😍', '🥰', '😘', '😎',
  '🤔', '😅', '😢', '😭', '😤', '🥺', '😱', '🤗',
  '👍', '👎', '👏', '🙌', '🤝', '💪', '🎉', '🔥',
  '❤️', '💔', '⭐', '🌟', '💯', '✅', '❌', '⚡',
  '🚀', '🎯', '💡', '📌', '📎', '📝', '💬', '🔔',
];

const imagePreviewCache = reactive<Record<string, string>>({});

const activeConversationId = computed(() => imStore.activeConversationId);
const activeConversation = computed(() => imStore.activeConversation);
const activeMessages = computed(() => imStore.activeMessages);

const sortedConversations = computed(() =>
  [...imStore.conversations].toSorted((a, b) => {
    const timeA = a.lastMessageAt ? new Date(a.lastMessageAt).getTime() : 0;
    const timeB = b.lastMessageAt ? new Date(b.lastMessageAt).getTime() : 0;
    return timeB - timeA;
  }),
);

function isSelfMessage(msg: ImApi.Message) {
  return msg.senderId === userStore.userInfo?.userId;
}

function formatTime(dateStr: string) {
  const date = new Date(dateStr);
  const now = new Date();
  if (date.toDateString() === now.toDateString()) {
    return date.toLocaleTimeString('zh-CN', {
      hour: '2-digit',
      minute: '2-digit',
    });
  }
  return date.toLocaleDateString('zh-CN', {
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
  });
}

function formatFileSize(bytes: number) {
  if (bytes < 1024) return `${bytes} B`;
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}

function openImage(url: string) {
  window.open(url, '_blank');
}

async function resolveImageUrl(msg: ImApi.Message) {
  const previewPath = msg.metadata?.imageUrl;
  if (!previewPath) return;

  if (imagePreviewCache[msg.id]) return;

  try {
    const result = await fileRequestClient.get<{ url: string }>(
      previewPath.replace(/^\/file-api/, ''),
    );
    if (result.url) {
      imagePreviewCache[msg.id] = result.url;
    }
  } catch {
    // preview failed, leave image broken
  }
}

async function selectConversation(conversationId: string) {
  imStore.setActiveConversation(conversationId);
  await imStore.loadMessages(conversationId);
  await nextTick();
  scrollToBottom();
  // Resolve image URLs
  for (const msg of imStore.activeMessages) {
    if (msg.contentType === 1 && msg.metadata?.imageUrl) {
      resolveImageUrl(msg);
    }
  }
  const msgs = imStore.activeMessages;
  if (msgs.length > 0) {
    const lastMsg = msgs.at(-1);
    if (lastMsg) {
      await imStore.markAsRead(conversationId, lastMsg.id);
    }
  }
}

async function handleSend(e?: any) {
  if (e?.shiftKey) return;
  e?.preventDefault?.();

  const content = inputMessage.value.trim();
  if (!content || !activeConversationId.value) return;

  sending.value = true;
  try {
    await imStore.sendMessage(activeConversationId.value, 0, content);
    inputMessage.value = '';
    showEmojiPicker.value = false;
    await nextTick();
    scrollToBottom();
  } catch {
    message.error('发送失败');
  } finally {
    sending.value = false;
  }
}

async function handleSendEmoji(emoji: string) {
  if (!activeConversationId.value) return;
  try {
    await imStore.sendMessage(activeConversationId.value, 4, emoji);
    showEmojiPicker.value = false;
    await nextTick();
    scrollToBottom();
  } catch {
    message.error('发送失败');
  }
}

async function handleImageUpload(e: Event) {
  const file = (e.target as HTMLInputElement).files?.[0];
  if (!file || !activeConversationId.value) return;

  if (!file.type.startsWith('image/')) {
    message.warning('请选择图片文件');
    return;
  }

  uploading.value = true;
  try {
    await uploadFileApi('im-files', file);
    const imageUrl = `/file-api/files/preview?bucket_name=im-files&object_key=${encodeURIComponent(file.name)}`;
    await imStore.sendMessage(activeConversationId.value, 1, '[图片]', {
      imageUrl,
      fileName: file.name,
      fileSize: file.size,
    });
    await nextTick();
    scrollToBottom();
  } catch {
    message.error('图片上传失败');
  } finally {
    uploading.value = false;
    (e.target as HTMLInputElement).value = '';
  }
}

async function handleFileUpload(e: Event) {
  const file = (e.target as HTMLInputElement).files?.[0];
  if (!file || !activeConversationId.value) return;

  uploading.value = true;
  try {
    await uploadFileApi('im-files', file);
    const fileUrl = `/file-api/files/download?bucket_name=im-files&object_key=${encodeURIComponent(file.name)}`;
    await imStore.sendMessage(activeConversationId.value, 2, file.name, {
      fileName: file.name,
      fileSize: file.size,
      fileUrl,
    });
    await nextTick();
    scrollToBottom();
  } catch {
    message.error('文件上传失败');
  } finally {
    uploading.value = false;
    (e.target as HTMLInputElement).value = '';
  }
}

function toggleEmojiPicker() {
  showEmojiPicker.value = !showEmojiPicker.value;
}

function handleClickOutside(e: MouseEvent) {
  const target = e.target as HTMLElement;
  if (!target.closest('.emoji-picker-area')) {
    showEmojiPicker.value = false;
  }
}

async function handleStartChat(user: ImApi.User) {
  try {
    await imStore.startPrivateChat(user.id);
    sidebarTab.value = 'messages';
    await nextTick();
    scrollToBottom();
  } catch {
    message.error('创建会话失败');
  }
}

async function handleCreateGroup() {
  if (!newGroupName.value.trim()) {
    message.warning('请输入群名称');
    return;
  }
  try {
    await createGroupApi({
      name: newGroupName.value,
      description: newGroupDesc.value || undefined,
      memberUserIds: selectedMemberIds.value,
    });
    message.success('群聊创建成功');
    showCreateGroup.value = false;
    newGroupName.value = '';
    newGroupDesc.value = '';
    selectedMemberIds.value = [];
    await imStore.loadConversations();
  } catch {
    message.error('创建失败');
  }
}

function handleContactSearch() {
  if (contactSearchTimer) clearTimeout(contactSearchTimer);
  contactSearchTimer = setTimeout(() => {
    imStore.searchContacts(contactSearchQuery.value || undefined);
  }, 300);
}

function handleMemberSearch(value: string) {
  memberSearchLoading.value = true;
  imStore.searchContacts(value || undefined).finally(() => {
    memberSearchLoading.value = false;
  });
}

function scrollToBottom() {
  if (messageListRef.value) {
    messageListRef.value.scrollTop = messageListRef.value.scrollHeight;
  }
}

async function onScroll() {
  if (!messageListRef.value || !activeConversationId.value) return;
  if (messageListRef.value.scrollTop === 0) {
    const msgs = imStore.activeMessages;
    const firstMsgId = msgs.length > 0 ? msgs[0]!.id : undefined;
    if (firstMsgId) {
      await imStore.loadMessages(activeConversationId.value, firstMsgId);
    }
  }
}

function switchToContacts() {
  sidebarTab.value = 'contacts';
  imStore.searchContacts();
}

onMounted(async () => {
  await imStore.connect();
  await imStore.loadConversations();
  await imStore.loadUnreadCounts();
  document.addEventListener('click', handleClickOutside);
});

onUnmounted(() => {
  imStore.disconnect();
  document.removeEventListener('click', handleClickOutside);
});
</script>

<template>
  <div
    class="flex h-[calc(100vh-120px)] overflow-hidden rounded-lg border border-border bg-card"
  >
    <!-- Sidebar -->
    <div class="flex w-[300px] shrink-0 flex-col border-r border-border">
      <!-- Tabs -->
      <div class="flex border-b border-border">
        <div
          class="flex-1 cursor-pointer px-4 py-3 text-center text-sm transition-colors"
          :class="
            sidebarTab === 'messages'
              ? 'border-b-2 border-primary font-medium text-foreground'
              : 'text-muted-foreground hover:text-foreground'
          "
          @click="sidebarTab = 'messages'"
        >
          消息
        </div>
        <div
          class="flex-1 cursor-pointer px-4 py-3 text-center text-sm transition-colors"
          :class="
            sidebarTab === 'contacts'
              ? 'border-b-2 border-primary font-medium text-foreground'
              : 'text-muted-foreground hover:text-foreground'
          "
          @click="switchToContacts"
        >
          通讯录
        </div>
      </div>

      <!-- Messages panel -->
      <template v-if="sidebarTab === 'messages'">
        <div
          class="flex items-center justify-between border-b border-border px-4 py-2"
        >
          <span class="text-sm text-muted-foreground">
            {{ sortedConversations.length }} 个会话
          </span>
          <Button type="primary" size="small" @click="showCreateGroup = true">
            创建群聊
          </Button>
        </div>
        <div class="flex-1 overflow-y-auto">
          <div
            v-for="conv in sortedConversations"
            :key="conv.id"
            class="flex cursor-pointer items-center px-4 py-3 transition-colors hover:bg-accent"
            :class="{
              'bg-primary/10 dark:bg-accent': conv.id === activeConversationId,
            }"
            @click="selectConversation(conv.id)"
          >
            <Avatar v-if="conv.type === 2" :size="40">
              {{ conv.groupName?.charAt(0) || '群' }}
            </Avatar>
            <Avatar v-else :size="40">
              {{ conv.otherUserName?.charAt(0) || 'U' }}
            </Avatar>

            <div class="ml-3 flex-1 overflow-hidden">
              <div class="truncate text-sm font-medium text-foreground">
                {{
                  conv.type === 2
                    ? conv.groupName
                    : conv.otherUserName || '私聊'
                }}
              </div>
              <div class="mt-1 truncate text-xs text-muted-foreground">
                {{ conv.lastMessageContent || '暂无消息' }}
              </div>
            </div>

            <Badge
              v-if="conv.unreadCount > 0"
              :count="conv.unreadCount"
              :overflow-count="99"
            />
          </div>
        </div>
      </template>

      <!-- Contacts panel -->
      <template v-else>
        <div class="border-b border-border px-3 py-2">
          <InputSearch
            v-model:value="contactSearchQuery"
            placeholder="搜索用户名或邮箱"
            @search="imStore.searchContacts(contactSearchQuery || undefined)"
            @change="handleContactSearch"
          />
        </div>
        <div class="flex-1 overflow-y-auto">
          <Spin :spinning="imStore.contactsLoading">
            <div
              v-for="user in imStore.contacts"
              :key="user.id"
              class="flex cursor-pointer items-center px-4 py-3 transition-colors hover:bg-accent"
              @click="handleStartChat(user)"
            >
              <Avatar :size="40">
                {{ user.username.charAt(0).toUpperCase() }}
              </Avatar>
              <div class="ml-3 flex-1 overflow-hidden">
                <div class="truncate text-sm font-medium text-foreground">
                  {{ user.username }}
                </div>
                <div class="mt-1 truncate text-xs text-muted-foreground">
                  {{ user.email }}
                </div>
              </div>
              <span
                v-if="imStore.onlineUsers.has(user.id)"
                class="mr-2 inline-block h-2 w-2 rounded-full bg-green-500"
              ></span>
            </div>
            <div
              v-if="!imStore.contactsLoading && imStore.contacts.length === 0"
              class="px-4 py-8 text-center text-sm text-muted-foreground"
            >
              没有找到用户
            </div>
          </Spin>
        </div>
      </template>
    </div>

    <!-- Main chat area -->
    <div class="flex flex-1 flex-col">
      <template v-if="activeConversation">
        <div
          class="flex items-center justify-between border-b border-border px-4 py-3 font-medium text-foreground"
        >
          <span>
            {{
              activeConversation.type === 2
                ? activeConversation.groupName
                : activeConversation.otherUserName || '私聊'
            }}
          </span>
          <Button
            v-if="activeConversation.type === 2"
            size="small"
            @click="showGroupManage = true"
          >
            群管理
          </Button>
        </div>

        <!-- Messages -->
        <div
          ref="messageListRef"
          class="flex-1 overflow-y-auto px-4 py-4"
          @scroll="onScroll"
        >
          <div
            v-for="msg in activeMessages"
            :key="msg.id"
            class="mb-4"
            :class="{ 'text-right': isSelfMessage(msg) }"
          >
            <div class="mb-1 text-xs text-muted-foreground">
              {{ msg.senderName || msg.senderId.substring(0, 8) }}
            </div>
            <div
              class="inline-block max-w-[60%] break-words rounded-lg px-3 py-2"
              :class="
                isSelfMessage(msg)
                  ? 'bg-primary text-primary-foreground'
                  : 'bg-muted text-foreground'
              "
            >
              <!-- Text -->
              <template v-if="msg.contentType === 0">
                {{ msg.content }}
              </template>
              <!-- Image -->
              <template v-else-if="msg.contentType === 1">
                <img
                  v-if="imagePreviewCache[msg.id]"
                  :src="imagePreviewCache[msg.id]"
                  class="max-w-[200px] cursor-pointer rounded-lg"
                  @click="openImage(imagePreviewCache[msg.id]!)"
                />
                <span
                  v-else
                  class="cursor-pointer text-xs underline"
                  @click="resolveImageUrl(msg)"
                >
                  [图片] 点击加载
                </span>
              </template>
              <!-- File -->
              <template v-else-if="msg.contentType === 2">
                <div class="flex items-center gap-2">
                  <span class="text-lg">📎</span>
                  <a
                    v-if="msg.metadata?.fileUrl"
                    :href="msg.metadata.fileUrl"
                    target="_blank"
                    class="underline"
                  >
                    {{ msg.content }}
                  </a>
                  <span v-else>{{ msg.content }}</span>
                  <span
                    v-if="msg.metadata?.fileSize"
                    class="text-xs opacity-70"
                  >
                    ({{ formatFileSize(msg.metadata.fileSize) }})
                  </span>
                </div>
              </template>
              <!-- Emoji -->
              <template v-else-if="msg.contentType === 4">
                <span class="text-3xl">{{ msg.content }}</span>
              </template>
              <!-- System -->
              <template v-else-if="msg.contentType === 3">
                <span class="text-xs italic opacity-80">{{ msg.content }}</span>
              </template>
            </div>
            <div class="mt-1 text-[11px] text-muted-foreground/60">
              {{ formatTime(msg.createdAt) }}
            </div>
          </div>
        </div>

        <!-- Input area -->
        <div class="emoji-picker-area relative border-t border-border">
          <!-- Emoji picker popup -->
          <div
            v-if="showEmojiPicker"
            class="absolute bottom-full right-0 mb-2 grid w-[280px] grid-cols-8 gap-1 rounded-lg border border-border bg-popover p-2 shadow-lg"
          >
            <button
              v-for="emoji in EMOJI_LIST"
              :key="emoji"
              class="flex h-8 w-8 cursor-pointer items-center justify-center rounded text-lg hover:bg-accent"
              @click="handleSendEmoji(emoji)"
            >
              {{ emoji }}
            </button>
          </div>

          <!-- Toolbar -->
          <div class="flex items-center gap-1 border-b border-border px-3 py-1.5">
            <button
              class="flex h-7 w-7 cursor-pointer items-center justify-center rounded text-base hover:bg-accent"
              title="表情"
              @click="toggleEmojiPicker"
            >
              😊
            </button>
            <button
              class="flex h-7 w-7 cursor-pointer items-center justify-center rounded text-base hover:bg-accent"
              title="图片"
              @click="imageInputRef?.click()"
            >
              🖼️
            </button>
            <button
              class="flex h-7 w-7 cursor-pointer items-center justify-center rounded text-base hover:bg-accent"
              title="文件"
              @click="fileInputRef?.click()"
            >
              📎
            </button>
          </div>

          <!-- Input row -->
          <div class="flex gap-2 px-3 py-2">
            <textarea
              v-model="inputMessage"
              class="flex-1 resize-none rounded-md border border-border bg-transparent px-3 py-1.5 text-sm outline-none focus:border-primary"
              placeholder="输入消息... (Shift+Enter 换行)"
              :rows="1"
              @keydown.enter="handleSend"
            />
            <Button
              type="primary"
              :loading="sending || uploading"
              @click="handleSend"
            >
              发送
            </Button>
          </div>

          <!-- Hidden file inputs -->
          <input
            ref="imageInputRef"
            type="file"
            accept="image/*"
            class="hidden"
            @change="handleImageUpload"
          />
          <input
            ref="fileInputRef"
            type="file"
            class="hidden"
            @change="handleFileUpload"
          />
        </div>
      </template>

      <div
        v-else
        class="flex flex-1 items-center justify-center text-muted-foreground"
      >
        <p>选择一个会话开始聊天</p>
      </div>
    </div>

    <!-- Create Group Modal -->
    <Modal
      v-model:open="showCreateGroup"
      title="创建群聊"
      @ok="handleCreateGroup"
    >
      <Form layout="vertical">
        <FormItem label="群名称">
          <Input v-model:value="newGroupName" />
        </FormItem>
        <FormItem label="群描述">
          <Input v-model:value="newGroupDesc" />
        </FormItem>
        <FormItem label="选择成员">
          <Select
            v-model:value="selectedMemberIds"
            mode="multiple"
            placeholder="搜索并选择成员"
            :filter-option="false"
            :loading="memberSearchLoading"
            @search="handleMemberSearch"
          >
            <SelectOption
              v-for="user in imStore.contacts"
              :key="user.id"
              :value="user.id"
            >
              {{ user.username }} ({{ user.email }})
            </SelectOption>
          </Select>
        </FormItem>
      </Form>
    </Modal>
  </div>
</template>
