<template>
  <div class="versioning-dialog" @click.self="$emit('close')">
    <div class="versioning-card" @click="closeScopeMenu">
      <header class="versioning-header">
        <div class="versioning-header-left">
          <h3>版本管理</h3>
          <label class="switch-line">
            <input
              type="checkbox"
              :checked="enabled"
              :disabled="loading"
              @change="$emit('toggle-enabled', ($event.target as HTMLInputElement).checked)"
            />
            <span class="switch"></span>
            <span class="switch-text">{{ enabled ? '开启' : '关闭' }}</span>
          </label>
          <div class="scope-line">
            <span class="scope-label">管理范围</span>
            <div
              class="scope-select"
              :class="{ open: scopeMenuOpen, disabled: !hostMode || loading || restoring }"
              @click.stop
            >
              <button
                type="button"
                class="scope-select-button"
                :disabled="!hostMode || loading || restoring"
                @click="toggleScopeMenu"
              >
                <span class="scope-select-value">{{ trackingModeLabel }}</span>
                <span class="scope-chevron" aria-hidden="true"></span>
              </button>
              <div v-if="scopeMenuOpen" class="scope-menu">
                <button
                  v-for="opt in scopeOptions"
                  :key="opt.value"
                  type="button"
                  class="scope-menu-option"
                  :class="{ selected: trackingMode === opt.value, disabled: opt.disabled }"
                  :disabled="opt.disabled"
                  @click="selectScope(opt.value)"
                >
                  <span class="scope-option-label">{{ opt.label }}</span>
                  <span
                    v-if="trackingMode === opt.value"
                    class="icon icon-sm scope-option-check"
                    :style="iconStyle('check')"
                    aria-hidden="true"
                  ></span>
                </button>
              </div>
            </div>
          </div>
        </div>
        <div class="versioning-header-actions">
          <button type="button" class="refresh-btn" :disabled="loading" @click="$emit('refresh')">
            <span class="icon icon-sm" :style="iconStyle('refreshCw')" aria-hidden="true"></span>
            <span>刷新</span>
          </button>
          <button type="button" class="icon-close-btn" aria-label="关闭" @click="$emit('close')">
            <span class="icon icon-sm" :style="iconStyle('x')" aria-hidden="true"></span>
          </button>
        </div>
      </header>

      <div class="versioning-body">
        <aside class="checkpoint-list scroll-area">
          <button
            v-for="item in orderedItems"
            :key="item.seq"
            type="button"
            class="checkpoint-item"
            :class="{ active: Number(selectedSeq) === Number(item.seq) }"
            @click="$emit('select', item.seq)"
          >
            <div class="row top">
              <span class="seq">#{{ item.seq }}</span>
              <span class="time">{{ formatTime(item.timestamp) }}</span>
            </div>
            <div class="preview">{{ item.message_preview || '(空消息)' }}</div>
            <div class="row stats">
              <span class="plus">+{{ item.insertions || 0 }}</span>
              <span class="minus">-{{ item.deletions || 0 }}</span>
              <span class="files">{{ item.files_changed || 0 }} 文件</span>
            </div>
          </button>
          <div v-if="!items.length" class="empty">暂无版本点</div>
        </aside>

        <section class="checkpoint-detail scroll-area">
          <div v-if="detailLoading" class="loading">加载详情中...</div>
          <template v-else-if="detail">
            <h4>提交详情 #{{ detail.seq }}</h4>
            <div class="summary">
              <span class="plus">+{{ detail.insertions || 0 }}</span>
              <span class="minus">-{{ detail.deletions || 0 }}</span>
              <span class="files">{{ detail.files_changed || 0 }} 文件</span>
            </div>
            <div class="file-list">
              <template v-for="(file, idx) in detail.files || []" :key="`${file.status}:${file.path}:${idx}`">
                <div class="file-row" :class="{ expanded: isFileExpanded(file, idx) }" @click="toggleFileExpand(file, idx)">
                  <span class="status">{{ file.status }}</span>
                  <span class="path">{{ file.path }}</span>
                  <span class="delta">
                    <span class="plus">+{{ file.insertions || 0 }}</span>
                    <span class="minus">-{{ file.deletions || 0 }}</span>
                  </span>
                </div>
                <div v-if="isFileExpanded(file, idx)" class="tool-result-diff scroll-area versioning-diff">
                  <div v-if="!(file.patch_lines || []).length" class="empty">暂无可展示的文本变更行</div>
                  <div
                    v-for="(line, lineIdx) in file.patch_lines || []"
                    :key="`line:${idx}:${lineIdx}`"
                    class="diff-line"
                    :class="line.type === 'add' ? 'diff-add' : (line.type === 'remove' ? 'diff-remove' : 'diff-context')"
                  >
                    {{ line.type === 'add' ? '+ ' : (line.type === 'remove' ? '- ' : '  ') }}{{ line.content }}
                  </div>
                  <div v-if="file.patch_truncated" class="approval-note">内容过长，已截断展示</div>
                </div>
              </template>
            </div>
          </template>
          <div v-else class="empty">请选择一个版本点查看详情</div>
        </section>
      </div>

      <footer class="versioning-footer">
        <div v-if="needWorkspaceMatch && workspaceMatched === false" class="workspace-mismatch-tip">
          当前对话所属工作区与当前工作区不一致，无法执行回溯。
        </div>
        <span class="restore-mode-label">回溯模式：覆盖当前对话</span>
        <button
          type="button"
          class="confirm-btn"
          :disabled="!enabled || selectedSeq === null || selectedSeq === undefined || restoring || (needWorkspaceMatch && workspaceMatched === false)"
          @click="$emit('confirm')"
        >
          {{ restoring ? '回溯中...' : '确认回溯' }}
        </button>
      </footer>
    </div>
  </div>
</template>

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

const props = defineProps<{
  hostMode: boolean;
  enabled: boolean;
  trackingMode: string;
  loading: boolean;
  items: any[];
  selectedSeq: number | null;
  detail: any;
  detailLoading: boolean;
  restoring: boolean;
  restoreMode: string;
  workspaceMatched?: boolean;
  iconStyle?: (key: string) => Record<string, string>;
}>();

const emit = defineEmits([
  'close',
  'refresh',
  'toggle-enabled',
  'update:tracking-mode',
  'select',
  'confirm',
  'update:restore-mode'
]);

const iconStyle = (key: string) => (props.iconStyle ? props.iconStyle(key) : {});

const needWorkspaceMatch = computed(() => String(props.trackingMode || '') !== 'conversation_only');

const scopeOptions = computed(() => [
  { value: 'workspace_and_conversation', label: '管理工作区和对话', disabled: !props.hostMode },
  { value: 'conversation_only', label: '仅管理对话', disabled: false }
]);

const trackingModeLabel = computed(() => {
  const found = scopeOptions.value.find((o) => o.value === props.trackingMode);
  return found ? found.label : '仅管理对话';
});

const scopeMenuOpen = ref(false);
const toggleScopeMenu = () => {
  if (!props.hostMode || props.loading || props.restoring) return;
  scopeMenuOpen.value = !scopeMenuOpen.value;
};
const closeScopeMenu = () => {
  scopeMenuOpen.value = false;
};
const selectScope = (value: string) => {
  scopeMenuOpen.value = false;
  if (value === props.trackingMode) return;
  emit('update:tracking-mode', value);
};

const orderedItems = computed(() => {
  const src = Array.isArray(props.items) ? props.items : [];
  return [...src].sort((a: any, b: any) => Number(a?.seq || 0) - Number(b?.seq || 0));
});

const expandedFileKey = ref<string | null>(null);
const fileKey = (file: any, idx: number) => `${file?.status || ''}:${file?.old_path || ''}:${file?.path || ''}:${idx}`;
const toggleFileExpand = (file: any, idx: number) => {
  const key = fileKey(file, idx);
  expandedFileKey.value = expandedFileKey.value === key ? null : key;
};
const isFileExpanded = (file: any, idx: number) => expandedFileKey.value === fileKey(file, idx);

watch(
  () => props.detail?.seq,
  () => {
    expandedFileKey.value = null;
  }
);

const formatTime = (value: string) => {
  if (!value) return '-';
  try {
    return new Date(value).toLocaleString('zh-CN', {
      month: '2-digit',
      day: '2-digit',
      hour: '2-digit',
      minute: '2-digit'
    });
  } catch {
    return value;
  }
};
</script>

<style scoped>
/* ===== 遮罩 + 窗口（单层圆角，最大尺寸） ===== */
.versioning-dialog {
  position: fixed;
  inset: 0;
  z-index: 1200;
  background: var(--theme-overlay-scrim);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  backdrop-filter: blur(8px);
}

.versioning-card {
  width: min(1100px, 96vw);
  max-width: 96vw;
  height: min(620px, 88vh);
  max-height: 88vh;
  overflow: hidden;
  border-radius: 16px;
  background: var(--claude-panel);
  border: 1px solid var(--claude-border);
  box-shadow: var(--theme-shadow-strong);
  display: flex;
  flex-direction: column;
  color: var(--claude-text);
}

/* ===== 头部：固定高度，靠分隔线 ===== */
.versioning-header {
  flex: 0 0 auto;
  height: 60px;
  padding: 0 18px;
  border-bottom: 1px solid var(--claude-border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.versioning-header-left {
  display: inline-flex;
  align-items: center;
  gap: 16px;
  min-width: 0;
}

.versioning-header h3 {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.versioning-header-actions {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

/* 自定义开关 */
.switch-line {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 38px;
  font-size: 14px;
  cursor: pointer;
  user-select: none;
}

.switch-line input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

.switch-line .switch {
  flex: 0 0 auto;
  width: 38px;
  height: 22px;
  border-radius: 999px;
  background: var(--theme-switch-track);
  position: relative;
  transition: background 0.2s ease;
}

.switch-line .switch::after {
  content: '';
  position: absolute;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--theme-surface-strong);
  top: 2px;
  left: 2px;
  transition: transform 0.2s ease;
}

.switch-line input:checked + .switch {
  background: var(--claude-accent-strong);
}

.switch-line input:checked + .switch::after {
  transform: translateX(16px);
}

.switch-line input:disabled + .switch {
  opacity: 0.5;
}

.switch-text {
  white-space: nowrap;
}

/* ===== 自定义下拉（管理范围） ===== */
.scope-line {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--claude-text-secondary);
}

.scope-label {
  white-space: nowrap;
}

.scope-select {
  position: relative;
}

.scope-select-button {
  height: 32px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 0 10px;
  border: 1px solid var(--claude-border);
  border-radius: 9px;
  background: transparent;
  color: var(--claude-text);
  font-size: 13px;
  cursor: pointer;
  transition:
    background 140ms ease,
    border-color 140ms ease;
}

.scope-select-button:hover:not(:disabled) {
  background: var(--theme-tab-active);
}

.scope-select.disabled .scope-select-button,
.scope-select-button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.scope-select-value {
  white-space: nowrap;
}

/* chevron：纯 CSS 箭头，视觉居中 */
.scope-chevron {
  width: 10px;
  height: 10px;
  flex: 0 0 auto;
  position: relative;
}

.scope-chevron::before {
  content: '';
  position: absolute;
  top: 1px;
  left: 1px;
  width: 6px;
  height: 6px;
  border-right: 1.5px solid var(--claude-text-secondary);
  border-bottom: 1.5px solid var(--claude-text-secondary);
  transform: rotate(45deg);
  transition: transform 160ms ease;
}

.scope-select.open .scope-chevron::before {
  transform: rotate(-135deg);
  top: 4px;
}

.scope-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  min-width: 100%;
  width: max-content;
  z-index: 20;
  padding: 6px;
  border: 1px solid var(--claude-border);
  border-radius: 12px;
  background: var(--theme-surface-strong);
  box-shadow: var(--theme-shadow-soft);
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.scope-menu-option {
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 0 10px;
  border: 0;
  border-radius: 9px;
  background: transparent;
  color: var(--claude-text);
  font-size: 13px;
  text-align: left;
  cursor: pointer;
  white-space: nowrap;
  transition: background 140ms ease;
}

.scope-menu-option:hover:not(:disabled) {
  background: var(--theme-tab-active);
}

.scope-menu-option.disabled,
.scope-menu-option:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.scope-option-check {
  flex: 0 0 auto;
  color: var(--claude-text-secondary);
}

/* ===== 头部按钮 ===== */
.refresh-btn {
  height: 32px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0 12px;
  border: 1px solid var(--claude-border);
  border-radius: 9px;
  background: transparent;
  color: var(--claude-text);
  font-size: 13px;
  cursor: pointer;
  transition: background 140ms ease;
}

.refresh-btn:hover:not(:disabled) {
  background: var(--theme-tab-active);
}

.refresh-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.icon-close-btn {
  width: 32px;
  height: 32px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 9px;
  background: transparent;
  color: var(--claude-text-secondary);
  cursor: pointer;
  transition:
    background 140ms ease,
    color 140ms ease;
}

.icon-close-btn:hover {
  background: var(--theme-tab-active);
  color: var(--claude-text);
}

/* ===== 主体：左右分栏靠竖线 ===== */
.versioning-body {
  display: grid;
  grid-template-columns: 360px 1fr;
  min-height: 0;
  flex: 1 1 auto;
}

/* 通用滚动容器：隐藏滚动条 */
.scroll-area {
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.scroll-area::-webkit-scrollbar {
  width: 0;
  height: 0;
}

.checkpoint-list {
  border-right: 1px solid var(--claude-border);
  padding: 6px 8px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* 版本点：扁平无边框，固定高度，靠 hover/active 底色区分 */
.checkpoint-item {
  width: 100%;
  height: 78px;
  flex: 0 0 78px;
  box-sizing: border-box;
  text-align: left;
  border: 0;
  border-radius: 10px;
  padding: 0 12px;
  background: transparent;
  color: var(--claude-text);
  cursor: pointer;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  transition: background 140ms ease;
}

.checkpoint-item:hover,
.checkpoint-item.active {
  background: var(--theme-tab-active);
}

.checkpoint-item.active {
  position: relative;
}

.checkpoint-item.active::before {
  content: '';
  position: absolute;
  left: 4px;
  top: 16px;
  bottom: 16px;
  width: 3px;
  border-radius: 999px;
  background: var(--claude-text-secondary);
}

.row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.row.top {
  font-size: 12px;
  color: var(--claude-text-secondary);
}

.seq {
  font-weight: 700;
  color: var(--claude-text);
}

.preview {
  font-size: 13px;
  line-height: 1.3;
  color: var(--claude-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.row.stats {
  font-size: 12px;
}

/* diff 红绿增删色：通用语义色，保留固定值，三模式下含义一致 */
.plus {
  color: var(--state-success);
}

.minus {
  color: var(--state-danger);
}

.files {
  color: var(--claude-text-secondary);
}

.checkpoint-detail {
  padding: 14px 16px;
}

.checkpoint-detail h4 {
  margin: 0 0 10px;
  font-size: 14px;
  font-weight: 700;
}

.summary {
  display: flex;
  gap: 12px;
  font-size: 13px;
  margin-bottom: 12px;
}

.file-list {
  display: flex;
  flex-direction: column;
}

/* 文件行：固定高度，靠虚线分隔 */
.file-row {
  display: grid;
  grid-template-columns: 52px 1fr auto;
  gap: 10px;
  align-items: center;
  min-height: 40px;
  border-bottom: 1px solid var(--claude-border);
  padding: 0 4px;
  font-size: 13px;
  cursor: pointer;
  border-radius: 8px;
  transition: background 140ms ease;
}

.file-row:hover {
  background: var(--theme-tab-active);
}

.file-row.expanded {
  background: var(--theme-tab-active);
}

.status {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  color: var(--claude-text-secondary);
}

.path {
  word-break: break-all;
  color: var(--claude-text);
}

.delta {
  display: inline-flex;
  gap: 8px;
}

.loading,
.empty {
  color: var(--claude-text-secondary);
  font-size: 13px;
  padding: 12px 4px;
}

/* ===== 底部：固定高度，靠分隔线 ===== */
.versioning-footer {
  flex: 0 0 auto;
  height: 60px;
  padding: 0 18px;
  border-top: 1px solid var(--claude-border);
  display: flex;
  align-items: center;
  gap: 12px;
  justify-content: flex-end;
}

.restore-mode-label {
  font-size: 13px;
  color: var(--claude-text-secondary);
}

.workspace-mismatch-tip {
  margin-right: auto;
  color: var(--claude-warning);
  font-size: 13px;
  font-weight: 600;
}

.confirm-btn {
  height: 38px;
  border: 0;
  border-radius: 10px;
  padding: 0 18px;
  font-size: 14px;
  font-weight: 600;
  background: var(--claude-accent);
  color: var(--on-accent);
  cursor: pointer;
  transition: background 140ms ease;
}

.confirm-btn:hover:not(:disabled) {
  background: var(--claude-button-hover);
}

.confirm-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ===== diff 展示：与文件编辑差异保持一致 ===== */
.tool-result-diff {
  margin-top: 10px;
  font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
  font-size: 12px;
  line-height: 1.5;
}

.tool-result-diff.scroll-area {
  max-height: calc(8 * 1.5em + 16px);
  border: 1px solid var(--claude-border);
  border-radius: 8px;
  padding: 8px;
  background: var(--theme-surface-soft);
}

.diff-line {
  padding: 2px 4px;
  margin: 0;
  white-space: pre-wrap;
  word-wrap: break-word;
}

/* diff 增删色：通用语义色，保留固定值 */
.diff-remove {
  background: var(--diff-del-bg);
  color: var(--state-danger);
}

.diff-add {
  background: var(--diff-add-bg);
  color: var(--state-success);
}

.diff-context {
  background: transparent;
  color: var(--claude-text-secondary);
}

.approval-note {
  padding: 6px 8px;
  font-size: 11px;
  color: var(--claude-text-secondary);
}

@media (max-width: 860px) {
  .versioning-body {
    grid-template-columns: 1fr;
    grid-template-rows: 1fr 1fr;
  }
  .checkpoint-list {
    border-right: none;
    border-bottom: 1px solid var(--claude-border);
  }
}
</style>
