<script setup lang="ts">
import type {
  AttachmentsProps,
  BubbleListProps,
  ConversationsProps,
  PromptsProps,
} from 'ant-design-x-vue';

import type { VNode } from 'vue';

import { computed, h, onMounted, ref, watch } from 'vue';

import {
  CloudUploadOutlined,
  CommentOutlined,
  CopyOutlined,
  DeleteOutlined,
  EllipsisOutlined,
  FireOutlined,
  HeartOutlined,
  PaperClipOutlined,
  PlusOutlined,
  ReadOutlined,
  ShareAltOutlined,
  SmileOutlined,
  SyncOutlined,
} from '@ant-design/icons-vue';
import VueOfficePptx from '@vue-office/pptx';
import {
  Badge,
  Button,
  Flex,
  message,
  Space,
  theme,
  Typography,
} from 'ant-design-vue';
import {
  Attachments,
  Bubble,
  Conversations,
  Prompts,
  Sender,
  useXAgent,
  useXChat,
  Welcome,
} from 'ant-design-x-vue';

import { getChatList, sendWorkflow } from '#/api';

defineOptions({ name: 'PlaygroundIndependentSetup' });

const { token } = theme.useToken();

const styles = computed(() => {
  return {
    layout: {
      width: '100%',
      'min-width': '1000px',
      height: '722px',
      'border-radius': `${token.value.borderRadius}px`,
      display: 'flex',
      background: `${token.value.colorBgContainer}`,
      'font-family': `AlibabaPuHuiTi, ${token.value.fontFamily}, sans-serif`,
    },
    menu: {
      background: `${token.value.colorBgLayout}80`,
      width: '280px',
      height: '100%',
      display: 'flex',
      'flex-direction': 'column',
    },
    conversations: {
      padding: '0 12px',
      flex: 1,
      'overflow-y': 'auto',
    },
    chat: {
      height: '100%',
      width: '100%',
      'max-width': '700px',
      margin: '0 auto',
      'box-sizing': 'border-box',
      display: 'flex',
      'flex-direction': 'column',
      padding: `${token.value.paddingLG}px`,
      gap: '16px',
    },
    messages: {
      flex: 1,
    },
    placeholder: {
      'padding-top': '32px',
      'text-align': 'left',
      flex: 1,
    },
    sender: {
      'box-shadow': token.value.boxShadow,
    },
    logo: {
      display: 'flex',
      height: '72px',
      'align-items': 'center',
      'justify-content': 'start',
      padding: '0 24px',
      'box-sizing': 'border-box',
    },
    'logo-img': {
      width: '24px',
      height: '24px',
      display: 'inline-block',
    },
    'logo-span': {
      display: 'inline-block',
      margin: '0 8px',
      'font-weight': 'bold',
      color: token.value.colorText,
      'font-size': '16px',
    },
    addBtn: {
      background: '#1677ff0f',
      border: '1px solid #1677ff34',
      width: 'calc(100% - 24px)',
      margin: '0 12px 24px 12px',
    },
  } as const;
});

const pptx = ref<any>('/static/43b7da46a6ca47e5a9d7710d8dcf499c.pptx');

const [messageApi, contextHolder] = message.useMessage();

const menuConfig: ConversationsProps['menu'] = (conversation) => ({
  items: [
    {
      label: '删除此对话',
      key: 'operation3',
      icon: h(DeleteOutlined),
      danger: true,
    },
  ],
  onClick: (menuInfo) => {
    messageApi.info(`Click ${conversation.key} - ${menuInfo.key}`);
  },
});

const acticeModeKey = ref('1');

// 定义模板数据
const templates = ref([
  { label: '模板1', key: '1' },
  { label: '模板2', key: '2' },
  { label: '模板3', key: '3' },
  { label: '模板34', key: '4' },
  { label: '模板35', key: '5' },
  { label: '模板36', key: '7' },
  { label: '模板37', key: '8' },
  { label: '模板38', key: '9' },
]);

// const sleep = () => new Promise(resolve => setTimeout(resolve, 500))

function renderTitle(icon: VNode, title: string) {
  return h(Space, { align: 'start' }, [icon, h('span', title)]);
}

const defaultConversationsItems = [
  {
    key: '0',
    label: 'What is Ant Design X?',
  },
];

const placeholderPromptsItems: PromptsProps['items'] = [
  {
    key: '1',
    label: renderTitle(
      h(FireOutlined, { style: { color: '#FF4D4F' } }),
      'Hot Topics',
    ),
    description: 'What are you interested in?',
    children: [
      {
        key: '1-1',
        description: `What's new in X?`,
      },
      {
        key: '1-2',
        description: `What's AGI?`,
      },
      {
        key: '1-3',
        description: `Where is the doc?`,
      },
    ],
  },
  {
    key: '2',
    label: renderTitle(
      h(ReadOutlined, { style: { color: '#1890FF' } }),
      'Design Guide',
    ),
    description: 'How to design a good product?',
    children: [
      {
        key: '2-1',
        icon: h(HeartOutlined),
        description: `Know the well`,
      },
      {
        key: '2-2',
        icon: h(SmileOutlined),
        description: `Set the AI role`,
      },
      {
        key: '2-3',
        icon: h(CommentOutlined),
        description: `Express the feeling`,
      },
    ],
  },
];

const senderPromptsItems: PromptsProps['items'] = [
  {
    key: '1',
    description: 'Hot Topics',
    icon: h(FireOutlined, { style: { color: '#FF4D4F' } }),
  },
  {
    key: '2',
    description: 'Design Guide',
    icon: h(ReadOutlined, { style: { color: '#1890FF' } }),
  },
];

const roles: BubbleListProps['roles'] = {
  ai: {
    placement: 'start',
    typing: { step: 5, interval: 20 },
    styles: {
      content: {
        borderRadius: '16px',
      },
    },
  },
  local: {
    placement: 'end',
    variant: 'shadow',
  },
};

// ==================== State ====================
const headerOpen = ref(false);
const content = ref('');
const conversationsItems = ref(defaultConversationsItems);
const activeKey = ref(defaultConversationsItems[0]?.key);
const attachedFiles = ref<AttachmentsProps['items']>([]);
const agentRequestLoading = ref(false);

// ==================== Runtime ====================
const [agent] = useXAgent({
  request: async ({ message }, { onSuccess }) => {
    agentRequestLoading.value = true;
    const res = await sendWorkflow(
      {
        appid: 'baca08c1-e92b-4dc9-a445-3584803f54d4',
      },
      {
        userId: '1563',
        conversationId: '',
        files: [],
        inputs: {
          declarationDoc: message,
        },
      },
    );
    agentRequestLoading.value = false;
    if (res.data.data.outputs.result) {
      onSuccess(`下载链接:${res.data.data.outputs.result}`);
      const url = new URL(res.data.data.outputs.result);
      pptx.value = url.pathname;
    } else {
      onSuccess('发生异常，可以输入更多信息再让我来回答或重试。');
    }
  },
});

const { onRequest, messages, setMessages } = useXChat({
  agent: agent?.value,
});

watch(
  activeKey,
  () => {
    if (activeKey.value !== undefined) {
      setMessages([]);
    }
  },
  { immediate: true },
);

// ==================== Event ====================
function onSubmit(nextContent: string) {
  if (!nextContent) return;
  onRequest(nextContent);
  // sendMessage(nextContent)
  content.value = '';
}

const onPromptsItemClick: PromptsProps['onItemClick'] = (info) => {
  onRequest(info.data.description as string);
};

function onAddConversation() {
  conversationsItems.value = [
    ...conversationsItems.value,
    {
      key: `${conversationsItems.value.length}`,
      label: `New Conversation ${conversationsItems.value.length}`,
    },
  ];
  activeKey.value = `${conversationsItems.value.length}`;
}

const onConversationClick: ConversationsProps['onActiveChange'] = (key) => {
  activeKey.value = key;
};

const handleFileChange: AttachmentsProps['onChange'] = (info) =>
  (attachedFiles.value = info.fileList);

// ==================== Nodes ====================
const placeholderNode = computed(() =>
  h(
    Space,
    { direction: 'vertical', size: 16, style: styles.value.placeholder },
    [
      h(Welcome, {
        variant: 'borderless',
        icon: 'https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*s5sNRo5LjfQAAAAAAAAAAAAADgCCAQ/fmt.webp',
        title: "Hello, I'm Ant Design X",
        description:
          'Base on Ant Design, AGI product interface solution, create a better intelligent vision~',
        extra: h(Space, {}, [
          h(Button, { icon: h(ShareAltOutlined) }),
          h(Button, { icon: h(EllipsisOutlined) }),
        ]),
      }),
      h(Prompts, {
        title: 'Do you want?',
        items: placeholderPromptsItems,
        styles: {
          list: {
            width: '100%',
          },
          item: {
            flex: 1,
          },
        },
        onItemClick: onPromptsItemClick,
      }),
    ],
  ),
);

const items = computed<BubbleListProps['items']>(() => {
  if (messages.value.length === 0) {
    return [{ content: placeholderNode, variant: 'borderless' }];
  }
  return messages.value.map(({ id, message, status }) => ({
    key: id,
    loading: status === 'loading',
    role: status === 'local' ? 'local' : 'ai',
    content: message,
  }));
});

// 自定义代码

// 获取会话记录
const getConversationList = async () => {
  const res = await getChatList(
    {
      appid: '363b9580-ae60-4a40-ae7d-ec434e86e326',
    },
    {
      userId: '1563',
      lastId: '',
      sortBy: '',
      limit: '5',
    },
  );
  if (res.status === 200) {
    conversationsItems.value = res.data.map((item: any) => {
      return {
        key: item.id,
        label: item.name,
      };
    });
    activeKey.value = res.data.data[0].id;
  }
};

const showQuoteButton = ref(false);
const selectedText = ref('');
const quoteButtonStyle = ref({
  position: 'absolute',
  top: '0',
  left: '0',
  display: 'none',
});

const handleTextSelection = (event: any) => {
  const selection = window.getSelection();
  if (selection && selection.toString().trim() !== '') {
    selectedText.value = selection.toString();

    // 获取鼠标位置
    const mouseX = event.pageX;
    const mouseY = event.pageY;

    // 设置按钮位置
    quoteButtonStyle.value = {
      position: 'fixed',
      top: `${mouseY}px`,
      left: `${mouseX}px`,
      display: 'block',
    };

    showQuoteButton.value = true;
  } else {
    showQuoteButton.value = false;
  }
};

const handleQuoteClick = () => {
  // 处理引用逻辑，比如将选中的文本添加到引用框中
  content.value = selectedText.value;
  showQuoteButton.value = false;
};

// 定义 pptx 的样式
const pptStyle = ref({
  height: 'calc(100vh - 150px)',
  width: '40%',
  margin: '30px 20px',
});

// 监听窗口大小变化
const handleResize = () => {
  // 动态调整宽度和高度
  pptStyle.value = {
    height: 'calc(100vh - 150px)', // 保持高度不变
    width: '40%', // 宽度为窗口宽度的 40%
    margin: '30px 20px',
  };
};

// 监听模板选择事件
const onModeClick: ConversationsProps['onActiveChange'] = (key) => {
  acticeModeKey.value = key;
};

const renderedHandler = () => {
  console.warn('渲染完成');
};
const errorHandler = () => {
  console.error('渲染失败');
};

onMounted(() => {
  getConversationList();
  window.addEventListener('resize', handleResize);
});
</script>

<template>
  <contextHolder />
  <div :style="styles.layout" style="height: calc(100vh - 70px)">
    <div :style="styles.menu">
      <!-- 🌟 Logo -->
      <div :style="styles.logo">
        <img
          src="https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*eco6RrQhxbMAAAAAAAAAAAAADgCCAQ/original"
          draggable="false"
          alt="logo"
          :style="styles['logo-img']"
        />
        <span :style="styles['logo-span']">PPT模板生成</span>
      </div>

      <!-- 🌟 添加会话 -->
      <Button type="link" :style="styles.addBtn" @click="onAddConversation">
        <PlusOutlined />
        新建会话
      </Button>

      <!-- 🌟 会话管理 -->
      <Conversations
        :items="conversationsItems"
        :style="styles.conversations"
        :active-key="activeKey"
        :menu="menuConfig"
        @active-change="onConversationClick"
      />

      <!-- 🌟 会话管理 -->
      <Typography.Title :level="5" style="margin: 0 0 8px">
        选择模板
      </Typography.Title>
      <Conversations
        :items="templates"
        :style="styles.conversations"
        :active-key="acticeModeKey"
        :menu="menuConfig"
        @active-change="onModeClick"
      />
    </div>

    <div :style="styles.chat" style="margin-left: 20px">
      <!-- 🌟 消息列表 -->
      <Bubble.List
        :items="items"
        :roles="roles"
        :style="styles.messages"
        @mouseup="handleTextSelection"
      >
        <template #footer>
          <Space :size="token.paddingXXS">
            <Button type="text" size="small" :icon="h(SyncOutlined)" />
            <Button type="text" size="small" :icon="h(CopyOutlined)" />
          </Space>
        </template>
      </Bubble.List>

      <a-button
        v-if="showQuoteButton"
        :style="quoteButtonStyle"
        @click="handleQuoteClick"
      >
        引用
      </a-button>

      <!-- 🌟 提示词 -->
      <Prompts :items="senderPromptsItems" @item-click="onPromptsItemClick" />

      <!-- 🌟 输入框 -->
      <Sender
        :value="content"
        :style="styles.sender"
        :loading="agentRequestLoading"
        @submit="onSubmit"
        @change="(value) => (content = value)"
      >
        <template #prefix>
          <Badge :dot="attachedFiles.length > 0 && !headerOpen">
            <Button type="text" @click="() => (headerOpen = !headerOpen)">
              <template #icon>
                <PaperClipOutlined />
              </template>
            </Button>
          </Badge>
        </template>

        <template #header>
          <Sender.Header
            title="Attachments"
            :open="headerOpen"
            :styles="{ content: { padding: 0 } }"
            @open-change="(open) => (headerOpen = open)"
          >
            <Attachments
              :before-upload="() => false"
              :items="attachedFiles"
              @change="handleFileChange"
            >
              <template #placeholder="type">
                <Flex
                  v-if="type && type.type === 'inline'"
                  align="center"
                  justify="center"
                  vertical
                  gap="2"
                >
                  <Typography.Text style="font-size: 30px; line-height: 1">
                    <CloudUploadOutlined />
                  </Typography.Text>
                  <Typography.Title
                    :level="5"
                    style="margin: 0; font-size: 14px; line-height: 1.5"
                  >
                    Upload files
                  </Typography.Title>
                  <Typography.Text type="secondary">
                    Click or drag files to this area to upload
                  </Typography.Text>
                </Flex>
                <Typography.Text v-if="type && type.type === 'drop'">
                  Drop file here
                </Typography.Text>
              </template>
            </Attachments>
          </Sender.Header>
        </template>
      </Sender>
    </div>
    <VueOfficePptx
      :src="pptx"
      :style="pptStyle"
      @rendered="renderedHandler"
      @error="errorHandler"
    />
  </div>
</template>
