<template>
  <div class="prompt-panel">
    <div class="messages" ref="messagesRef">
      <div
        v-for="(pair, pi) in pairs"
        :key="pair.assistantMsg?.id ?? 'user-' + pair.index"
        class="message-pair"
        :class="{ 'has-delete': pair.assistantMsg?.id && !streaming }"
      >
        <!-- Delete button: only shown on hover when pair has assistant id and not streaming -->
        <button
          v-if="pair.assistantMsg?.id && !streaming"
          class="pair-delete-btn"
          @click="deletePair(pair.assistantMsg!.id!)"
          title="删除这轮对话及关联提交"
        >
          <Icon icon="lucide:trash-2" :width="14" />
        </button>

        <!-- User message -->
        <div class="message user">
          <div class="message-role">我</div>
          <div class="message-content" v-html="renderContent(pair.userMsg)"></div>
        </div>

        <!-- Assistant message -->
        <div v-if="pair.assistantMsg" class="message assistant">
          <div class="message-role">AI</div>
          <div class="message-content" v-html="renderContent(pair.assistantMsg)"></div>
        </div>
      </div>

      <!-- Streaming indicator -->
      <div v-if="streaming" class="message assistant">
        <div class="message-role">AI</div>
        <div v-if="!streamingContent" class="typing-indicator">
          <span></span><span></span><span></span>
        </div>
        <div
          v-else
          class="message-content"
          v-html="renderMarkdown(streamingContent)"
        ></div>
        <div class="streaming-hint">AI 正在思考中…</div>
      </div>
    </div>
    <div class="input-area">
      <n-input
        v-model:value="input"
        type="textarea"
        :autosize="{ minRows: 1, maxRows: 4 }"
        placeholder="描述你想要的网页效果..."
        :disabled="streaming"
        @keydown.enter.exact.prevent="send"
      />
      <n-flex justify="flex-end" align="center" style="margin-top: 8px">
        <n-select
          v-model:value="selectedModel"
          :options="modelOptions"
          style="width: 120px"
          :disabled="streaming"
        />
        <n-button v-if="streaming" type="error" @click="stopPrompt">
          停止
        </n-button>
        <n-button
          v-else
          type="primary"
          :disabled="!input.trim() || !connected"
          @click="send"
        >
          发送
        </n-button>
      </n-flex>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, watch, nextTick, computed } from "vue"
import { useStorage } from "@vueuse/core"
import { marked, Renderer } from "marked"
import { useMessage } from "naive-ui"
import { Icon } from "@iconify/vue"
import {
  messages,
  streaming,
  streamingContent,
  connected,
  sendPrompt,
  stopPrompt,
} from "../../store/prompt"
import { Prompt } from "../../api"

const input = ref("")
const messagesRef = ref<HTMLElement>()
const naiveMessage = useMessage()

const modelOptions = [
  { label: "豆包", value: "doubao-seed-2-0-lite-260215" },
  { label: "DeepSeek", value: "deepseek-v4-flash" },
]
const selectedModel = useStorage("prompt-model", "deepseek-v4-flash")

// Group messages into user+assistant pairs
const pairs = computed(() => {
  const result: Array<{
    userMsg: { role: string; content: string; id?: number }
    assistantMsg: { role: string; content: string; id?: number; code?: any } | null
    index: number
  }> = []
  const msgs = messages.value
  let i = 0
  while (i < msgs.length) {
    if (msgs[i].role === "user") {
      const assistantMsg = msgs[i + 1]?.role === "assistant" ? msgs[i + 1] : null
      result.push({ userMsg: msgs[i], assistantMsg, index: i })
      i += assistantMsg ? 2 : 1
    } else {
      i++
    }
  }
  return result
})

async function deletePair(assistantMsgId: number) {
  try {
    await Prompt.deleteMessagePair(assistantMsgId)
    const msgIdx = messages.value.findIndex((m) => m.id === assistantMsgId)
    if (msgIdx >= 1) {
      messages.value.splice(msgIdx - 1, 2)
    }
    naiveMessage.success("已删除")
  } catch {
    naiveMessage.error("删除失败，请重试")
  }
}

function send() {
  const text = input.value.trim()
  if (!text || streaming.value) return
  sendPrompt(text, selectedModel.value)
  input.value = ""
}

const renderer = new Renderer()
renderer.code = function ({ lang }: { text: string; lang?: string }) {
  const label = lang ? lang.toUpperCase() : "CODE"
  const colors: Record<
    string,
    { bg: string; fg: string; dot: string; border: string; shimmer: string }
  > = {
    html: {
      bg: "#f0fff4",
      fg: "#18a058",
      dot: "#18a058",
      border: "#b8e8cc",
      shimmer: "#f0fff4, #e0f7ea, #f0fff4",
    },
    css: {
      bg: "#f0f0ff",
      fg: "#6060d0",
      dot: "#6060d0",
      border: "#d0d0f0",
      shimmer: "#f0f0ff, #e8e8fa, #f0f0ff",
    },
    js: {
      bg: "#fffbf0",
      fg: "#c0960a",
      dot: "#c0960a",
      border: "#f0e0b0",
      shimmer: "#fffbf0, #fff5e0, #fffbf0",
    },
    javascript: {
      bg: "#fffbf0",
      fg: "#c0960a",
      dot: "#c0960a",
      border: "#f0e0b0",
      shimmer: "#fffbf0, #fff5e0, #fffbf0",
    },
  }
  const c = colors[(lang ?? "").toLowerCase()] ?? {
    bg: "#f0f7ff",
    fg: "#2080f0",
    dot: "#2080f0",
    border: "#e0eaf5",
    shimmer: "#f0f7ff, #e8f4f8, #f0f7ff",
  }
  return `<div class="code-placeholder" style="background: linear-gradient(90deg, ${c.shimmer}); background-size: 200% 100%; border-color: ${c.border}"><span class="code-placeholder-dot" style="background: ${c.dot}"></span><span class="code-placeholder-label" style="color: ${c.fg}; background: ${c.fg}18">${label}</span><span class="code-placeholder-text">代码正在生成中，结束后会自动应用到预览区</span></div>`
}

function renderMarkdown(text: string): string {
  return marked.parse(text, { renderer }) as string
}

function renderContent(msg: { role: string; content: string }): string {
  return renderMarkdown(msg.content)
}

watch([() => messages.value.length, streamingContent], () => {
  nextTick(() => {
    if (messagesRef.value) {
      messagesRef.value.scrollTop = messagesRef.value.scrollHeight
    }
  })
})
</script>

<style scoped>
.prompt-panel {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}

.messages {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 12px;
}

.message {
  margin-bottom: 16px;
}

.message-role {
  font-size: 12px;
  font-weight: bold;
  margin-bottom: 4px;
  color: #666;
}

.message.user .message-role {
  color: #2080f0;
}

.message.assistant .message-role {
  color: #18a058;
}

.message-content {
  font-size: 14px;
  line-height: 1.6;
}

.message-content :deep(pre) {
  background: #f5f5f5;
  padding: 8px 12px;
  border-radius: 4px;
  overflow-x: auto;
  font-size: 13px;
}

.message-content :deep(.code-placeholder) {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  margin: 8px 0;
  background: linear-gradient(90deg, #f0f7ff, #e8f4f8, #f0f7ff);
  background-size: 200% 100%;
  animation: shimmer 2s ease-in-out infinite;
  border-radius: 6px;
  border: 1px solid #e0eaf5;
}

.message-content :deep(.code-placeholder-dot) {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #2080f0;
  animation: pulse 1.5s ease-in-out infinite;
}

.message-content :deep(.code-placeholder-label) {
  font-size: 11px;
  font-weight: 600;
  padding: 1px 6px;
  border-radius: 3px;
}

.message-content :deep(.code-placeholder-text) {
  font-size: 12px;
  color: #888;
}

@keyframes shimmer {
  0% {
    background-position: -200% 0;
  }
  100% {
    background-position: 200% 0;
  }
}

@keyframes pulse {
  0%,
  100% {
    opacity: 0.4;
  }
  50% {
    opacity: 1;
  }
}

.typing-indicator {
  display: flex;
  gap: 5px;
  padding: 8px 0;
}

.typing-indicator span {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #18a058;
  animation: bounce 1.4s ease-in-out infinite;
}

.typing-indicator span:nth-child(2) {
  animation-delay: 0.2s;
}

.typing-indicator span:nth-child(3) {
  animation-delay: 0.4s;
}

@keyframes bounce {
  0%,
  60%,
  100% {
    transform: translateY(0);
    opacity: 0.4;
  }
  30% {
    transform: translateY(-6px);
    opacity: 1;
  }
}

.streaming-hint {
  font-size: 11px;
  color: #aaa;
  margin-top: 4px;
  animation: pulse 1.5s ease-in-out infinite;
}

.input-area {
  flex-shrink: 0;
  padding: 12px;
  border-top: 1px solid #e0e0e0;
}

.message-pair {
  position: relative;
  margin-bottom: 4px;
}

.message-pair .message {
  margin-bottom: 16px;
}

.pair-delete-btn {
  display: none;
  position: absolute;
  top: 0;
  right: 0;
  background: none;
  border: 1px solid #e0e0e0;
  border-radius: 4px;
  padding: 3px 6px;
  cursor: pointer;
  color: #bbb;
  line-height: 1;
  transition: color 0.15s, border-color 0.15s;
}

.pair-delete-btn:hover {
  color: #e03e3e;
  border-color: #e03e3e;
}

.message-pair.has-delete:hover .pair-delete-btn {
  display: inline-flex;
  align-items: center;
}
</style>
