<script setup lang="ts">
import { computed } from 'vue';

import type { ChatThinkingBlockProps } from './types';

defineOptions({
  name: 'ChatThinkingBlock',
});

const props = withDefaults(defineProps<ChatThinkingBlockProps>(), {
  content: '',
  disabled: false,
  emptyBehavior: 'hide',
  expanded: false,
  label: '',
  readonly: false,
  status: 'end',
  summary: '',
});

const emit = defineEmits<{
  'update:expanded': [boolean];
}>();

const normalizedContent = computed(() =>
  String(props.content || '')
    .replace(/\r\n/g, '\n')
    .replace(/^\s*\n+/, '')
    .trimEnd(),
);

const shouldRender = computed(
  () =>
    normalizedContent.value.length > 0 || props.emptyBehavior === 'placeholder',
);

const expandedModel = computed({
  get: () => props.expanded,
  set: (value: boolean) => emit('update:expanded', value),
});

const computedLabel = computed(() => {
  if (props.label) {
    return props.label;
  }
  if (props.status === 'thinking') {
    return '思考中';
  }
  if (props.status === 'error') {
    return '思考异常';
  }
  return '已思考';
});

const computedSummary = computed(() => {
  if (props.summary) {
    return props.summary;
  }
  const source = normalizedContent.value
    .split('\n')
    .map((line) => line.trim())
    .find(Boolean);
  if (!source) {
    return props.emptyBehavior === 'placeholder' ? '暂无思考内容' : '';
  }
  return source.length > 56 ? `${source.slice(0, 56)}...` : source;
});

const canToggle = computed(
  () => !props.disabled && normalizedContent.value.length > 0,
);

function toggleExpanded() {
  if (!canToggle.value) {
    return;
  }
  expandedModel.value = !expandedModel.value;
}
</script>

<template>
  <div
    v-if="shouldRender"
    class="chat-thinking-block"
    :class="[
      `is-${status}`,
      {
        'is-disabled': disabled,
        'is-expanded': expandedModel,
        'is-readonly': readonly,
      },
    ]"
  >
    <button
      type="button"
      class="chat-thinking-block__trigger"
      :disabled="!canToggle"
      @click="toggleExpanded"
    >
      <span class="chat-thinking-block__leading">
        <span class="chat-thinking-block__indicator" aria-hidden="true"></span>
        <span class="chat-thinking-block__label">{{ computedLabel }}</span>
      </span>

      <span
        v-if="!expandedModel && computedSummary"
        class="chat-thinking-block__summary"
      >
        {{ computedSummary }}
      </span>

      <span
        class="chat-thinking-block__chevron"
        :class="{ 'is-open': expandedModel }"
        aria-hidden="true"
      ></span>
    </button>

    <transition name="chat-thinking-block__body-transition">
      <div
        v-if="expandedModel && normalizedContent"
        class="chat-thinking-block__body"
      >
        <div class="chat-thinking-block__content">
          {{ normalizedContent }}
        </div>
      </div>
    </transition>
  </div>
</template>

<style scoped>
.chat-thinking-block {
  border: 1px solid hsl(var(--divider-faint) / 0.18);
  border-radius: 16px;
  background:
    linear-gradient(
      180deg,
      hsl(var(--glass-tint) / 0.48) 0%,
      hsl(var(--surface-panel) / 0.74) 100%
    );
  box-shadow:
    inset 0 1px 0 hsl(var(--glass-border) / 0.24),
    0 10px 24px -24px hsl(var(--foreground) / 0.18);
  backdrop-filter: blur(12px);
}

.chat-thinking-block__trigger {
  display: grid;
  width: 100%;
  min-width: 0;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  color: inherit;
  text-align: left;
  background: transparent;
  border: 0;
  border-radius: inherit;
  transition: background-color 0.18s ease;
}

.chat-thinking-block__trigger:not(:disabled) {
  cursor: pointer;
}

.chat-thinking-block__trigger:not(:disabled):hover {
  background: hsl(var(--surface-contrast-soft) / 0.34);
}

.chat-thinking-block__trigger:disabled {
  cursor: default;
}

.chat-thinking-block__leading {
  display: inline-flex;
  min-width: 0;
  align-items: center;
  gap: 8px;
}

.chat-thinking-block__indicator {
  position: relative;
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: hsl(var(--text-muted) / 0.74);
}

.chat-thinking-block.is-thinking .chat-thinking-block__indicator {
  background: hsl(var(--primary) / 0.82);
  box-shadow: 0 0 0 4px hsl(var(--primary) / 0.12);
  animation: chat-thinking-pulse 1.8s ease-in-out infinite;
}

.chat-thinking-block.is-error .chat-thinking-block__indicator {
  background: hsl(var(--destructive) / 0.86);
  box-shadow: 0 0 0 4px hsl(var(--destructive) / 0.1);
}

.chat-thinking-block__label {
  font-size: 12px;
  font-weight: 600;
  line-height: 1.2;
  color: hsl(var(--text-strong));
  white-space: nowrap;
}

.chat-thinking-block__summary {
  min-width: 0;
  overflow: hidden;
  font-size: 12px;
  line-height: 1.3;
  color: hsl(var(--text-muted));
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chat-thinking-block__chevron {
  width: 9px;
  height: 9px;
  border-right: 1.5px solid hsl(var(--text-muted));
  border-bottom: 1.5px solid hsl(var(--text-muted));
  transform: rotate(45deg) translateY(-1px);
  transition: transform 0.18s ease;
}

.chat-thinking-block__chevron.is-open {
  transform: rotate(225deg) translateY(-1px);
}

.chat-thinking-block__body {
  padding: 0 12px 12px;
}

.chat-thinking-block__content {
  margin: 0;
  padding: 10px 12px;
  border-radius: 12px;
  background: hsl(var(--surface-panel) / 0.72);
  font-size: 12px;
  line-height: 1.68;
  color: hsl(var(--text-secondary));
  white-space: pre-wrap;
  word-break: break-word;
}

.chat-thinking-block.is-disabled {
  opacity: 0.82;
}

.chat-thinking-block__body-transition-enter-active,
.chat-thinking-block__body-transition-leave-active {
  transition:
    opacity 0.18s ease,
    transform 0.18s ease;
}

.chat-thinking-block__body-transition-enter-from,
.chat-thinking-block__body-transition-leave-to {
  opacity: 0;
  transform: translateY(-4px);
}

@keyframes chat-thinking-pulse {
  0%,
  100% {
    box-shadow: 0 0 0 4px hsl(var(--primary) / 0.12);
    opacity: 0.92;
  }

  50% {
    box-shadow: 0 0 0 7px hsl(var(--primary) / 0.04);
    opacity: 1;
  }
}
</style>
