<template>
  <div class="sort-visualizer">
    <div class="viz-header">
      <h3 class="viz-title">{{ title }}</h3>
      <div class="viz-controls">
        <button class="ctrl-btn" @click="randomize" title="随机生成新数组">🎲</button>
        <button class="ctrl-btn" @click="reset" title="重置">⏮</button>
        <button class="ctrl-btn" @click="prevStep" :disabled="currentStep <= 0" title="上一步">◀</button>
        <button class="ctrl-btn play-btn" @click="togglePlay" :title="isPlaying ? '暂停' : '播放'">
          {{ isPlaying ? '⏸' : '▶' }}
        </button>
        <button class="ctrl-btn" @click="nextStep" :disabled="currentStep >= totalSteps - 1" title="下一步">▶</button>
        <button class="ctrl-btn" @click="goToEnd" :disabled="currentStep >= totalSteps - 1" title="跳到结束">⏭</button>
        <span class="step-info">{{ currentStep + 1 }} / {{ totalSteps }}</span>
      </div>
      <div class="speed-control">
        <label>速度</label>
        <input type="range" min="1" max="10" v-model.number="speed" class="speed-slider" />
      </div>
    </div>

    <div class="viz-canvas-wrapper">
      <div class="viz-canvas" ref="canvasRef">
        <div
          v-for="(val, idx) in currentState.array"
          :key="idx"
          class="bar-wrapper"
          :style="{ height: barHeight(val) + 'px' }"
        >
          <div
            class="bar"
            :class="barClass(idx)"
            :style="{ height: '100%' }"
          >
            <span class="bar-value" v-if="showValues">{{ val }}</span>
          </div>
        </div>
      </div>
    </div>

    <div class="viz-description">
      <span class="desc-text">{{ currentState.description }}</span>
      <div class="legend">
        <span class="legend-item"><span class="legend-color legend-default"></span>未处理</span>
        <span class="legend-item"><span class="legend-color legend-comparing"></span>比较中</span>
        <span class="legend-item"><span class="legend-color legend-swapping"></span>交换</span>
        <span class="legend-item"><span class="legend-color legend-pivot"></span>基准</span>
        <span class="legend-item"><span class="legend-color legend-sorted"></span>已排序</span>
        <span class="legend-item"><span class="legend-color legend-merging"></span>归并中</span>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive, computed, watch, onBeforeUnmount } from 'vue'
import { generateMergeSortSteps, generateQuickSortSteps, generateRandomArray } from '../utils/sortAnimations.js'

const props = defineProps({
  title: { type: String, default: '排序可视化' },
  algorithm: { type: String, default: 'merge' }, // 'merge' | 'quick'
  arraySize: { type: Number, default: 12 },
  showValues: { type: Boolean, default: true }
})

const canvasRef = ref(null)
const currentStep = ref(0)
const isPlaying = ref(false)
const speed = ref(5)
let timer = null

const rawArray = ref(generateRandomArray(props.arraySize))
const steps = ref([])
const totalSteps = computed(() => steps.value.length)

const currentState = computed(() => {
  if (steps.value.length === 0) {
    return {
      array: rawArray.value,
      highlights: {},
      description: '点击 ▶ 开始演示'
    }
  }
  return steps.value[currentStep.value] || steps.value[0]
})

// 计算最大值用于柱状图高度
const maxVal = computed(() => {
  return Math.max(...currentState.value.array, 1)
})

function barHeight(val) {
  // 最大高度约 280px
  return Math.max(20, (val / maxVal.value) * 260)
}

function barClass(idx) {
  const h = currentState.value.highlights || {}
  const classes = []

  // 已排序（最终位置）
  if (h.sorted && h.sorted.includes(idx)) {
    classes.push('bar-sorted')
    return classes
  }
  if (h.sortedIndices && h.sortedIndices.includes(idx)) {
    classes.push('bar-sorted')
    return classes
  }

  // 基准元素
  if (h.pivot === idx) {
    classes.push('bar-pivot')
    return classes
  }

  // 交换中
  if (h.swapping && h.swapping.includes(idx)) {
    classes.push('bar-swapping')
    return classes
  }

  // 比较中
  if (h.comparing && h.comparing.includes(idx)) {
    classes.push('bar-comparing')
    return classes
  }

  // 归并范围
  if (h.merging) {
    const l = h.merging.left
    const r = h.merging.right
    if (idx >= l[0] && idx <= l[1]) classes.push('bar-merging-left')
    else if (idx >= r[0] && idx <= r[1]) classes.push('bar-merging-right')
  }

  // 范围高亮
  if (h.range && !classes.length) {
    if (idx >= h.range[0] && idx <= h.range[1]) {
      classes.push('bar-in-range')
    }
  }

  return classes
}

// 生成动画步骤
function generateSteps() {
  if (props.algorithm === 'merge') {
    steps.value = generateMergeSortSteps(rawArray.value)
  } else {
    steps.value = generateQuickSortSteps(rawArray.value)
  }
  currentStep.value = 0
}

function randomize() {
  stopPlay()
  rawArray.value = generateRandomArray(props.arraySize)
  generateSteps()
}

function reset() {
  stopPlay()
  rawArray.value = generateRandomArray(props.arraySize)
  generateSteps()
}

function nextStep() {
  if (currentStep.value < steps.value.length - 1) {
    currentStep.value++
  } else {
    stopPlay()
  }
}

function prevStep() {
  if (currentStep.value > 0) {
    currentStep.value--
  }
}

function goToEnd() {
  stopPlay()
  currentStep.value = steps.value.length - 1
}

function togglePlay() {
  if (isPlaying.value) {
    stopPlay()
  } else {
    startPlay()
  }
}

function startPlay() {
  if (currentStep.value >= steps.value.length - 1) {
    currentStep.value = 0
  }
  isPlaying.value = true
  const interval = Math.max(50, 600 - speed.value * 50)
  timer = setInterval(() => {
    if (currentStep.value < steps.value.length - 1) {
      currentStep.value++
    } else {
      stopPlay()
    }
  }, interval)
}

function stopPlay() {
  isPlaying.value = false
  if (timer) {
    clearInterval(timer)
    timer = null
  }
}

onBeforeUnmount(() => {
  stopPlay()
})

// 初始化
generateSteps()
</script>

<style scoped>
.sort-visualizer {
  background: var(--card-bg);
  border: 1px solid var(--border-color);
  border-radius: 16px;
  overflow: hidden;
  margin-bottom: 24px;
  box-shadow: var(--shadow-sm);
}

.viz-header {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  padding: 14px 20px;
  background: var(--hover-bg);
  border-bottom: 1px solid var(--border-color);
}

.viz-title {
  font-size: 16px;
  font-weight: 700;
  color: var(--text-primary);
  margin-right: auto;
}

.viz-controls {
  display: flex;
  align-items: center;
  gap: 6px;
}

.ctrl-btn {
  background: var(--card-bg);
  border: 1px solid var(--border-color);
  border-radius: 8px;
  padding: 6px 10px;
  font-size: 16px;
  cursor: pointer;
  transition: all 0.15s;
  line-height: 1;
}

.ctrl-btn:hover:not(:disabled) {
  background: var(--active-bg);
  border-color: var(--primary-color);
}

.ctrl-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

.play-btn {
  background: var(--primary-color);
  color: white;
  border-color: var(--primary-color);
}

.play-btn:hover:not(:disabled) {
  opacity: 0.9;
}

.step-info {
  font-size: 12px;
  color: var(--text-tertiary);
  font-family: var(--mono);
  min-width: 60px;
  text-align: center;
}

.speed-control {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--text-tertiary);
}

.speed-slider {
  width: 60px;
  accent-color: var(--primary-color);
}

/* 画布 */
.viz-canvas-wrapper {
  padding: 24px 20px 12px;
  overflow-x: auto;
}

.viz-canvas {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 3px;
  min-height: 300px;
  padding: 0 10px;
}

.bar-wrapper {
  flex: 1;
  min-width: 18px;
  max-width: 48px;
  display: flex;
  align-items: flex-end;
  transition: height 0.2s ease;
}

.bar {
  width: 100%;
  border-radius: 4px 4px 0 0;
  background: var(--primary-color);
  opacity: 0.75;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  transition: all 0.2s ease;
  min-height: 4px;
  position: relative;
}

.bar-value {
  font-size: 10px;
  color: white;
  font-weight: 700;
  position: absolute;
  top: -18px;
  text-shadow: 0 1px 2px rgba(0,0,0,0.3);
  font-family: var(--mono);
}

/* 状态颜色 */
.bar-comparing {
  background: #f59e0b;
  opacity: 1;
  transform: scaleY(1.02);
  box-shadow: 0 0 8px rgba(245, 158, 11, 0.5);
}

.bar-swapping {
  background: #ef4444;
  opacity: 1;
  transform: scaleY(1.05);
  box-shadow: 0 0 12px rgba(239, 68, 68, 0.5);
  animation: pulse 0.3s ease;
}

.bar-pivot {
  background: #8b5cf6;
  opacity: 1;
  transform: scaleY(1.05);
  box-shadow: 0 0 12px rgba(139, 92, 246, 0.5);
}

.bar-sorted {
  background: #22c55e;
  opacity: 0.9;
}

.bar-in-range {
  opacity: 0.85;
}

.bar-merging-left {
  background: #3b82f6;
  opacity: 0.9;
}

.bar-merging-right {
  background: #06b6d4;
  opacity: 0.9;
}

@keyframes pulse {
  0%, 100% { transform: scaleY(1.05); }
  50% { transform: scaleY(1.15); }
}

/* 描述和图例 */
.viz-description {
  padding: 10px 20px 14px;
  border-top: 1px solid var(--border-color);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
}

.desc-text {
  font-size: 14px;
  color: var(--text-primary);
  font-weight: 500;
  flex: 1;
}

.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  font-size: 11px;
  color: var(--text-tertiary);
}

.legend-item {
  display: flex;
  align-items: center;
  gap: 4px;
}

.legend-color {
  width: 12px;
  height: 12px;
  border-radius: 3px;
  display: inline-block;
}

.legend-default {
  background: var(--primary-color);
  opacity: 0.75;
}
.legend-comparing {
  background: #f59e0b;
}
.legend-swapping {
  background: #ef4444;
}
.legend-pivot {
  background: #8b5cf6;
}
.legend-sorted {
  background: #22c55e;
}
.legend-merging {
  background: #06b6d4;
}
</style>
