<script setup lang="ts">
import api from '@/api'
import type { Plugin } from '@/api/types'
import { getLogoUrl } from '@/utils/imageUtils'
import { useI18n } from 'vue-i18n'
import { useRecentPlugins } from '@/composables/useRecentPlugins'
import PluginDataDialog from '@/components/dialog/PluginDataDialog.vue'
import { VCard } from 'vuetify/components'
import { getDominantColor } from '@/@core/utils/image'
import { disableBodyScroll, enableBodyScroll } from 'body-scroll-lock'

// 国际化
const { t } = useI18n()

// 最近访问插件管理
const { getRecentPlugins, addRecentPlugin } = useRecentPlugins()

// 输入参数
const props = defineProps({
  visible: {
    type: Boolean,
    default: false,
  },
  pullDistance: {
    type: Number,
    default: 0,
  },
})

// 事件
const emit = defineEmits<{
  (e: 'close'): void
  (e: 'plugin-click', plugin: Plugin): void
}>()

// 有详情页面的插件列表
const pluginsWithPage = ref<Plugin[]>([])

// 最近访问的插件列表
const recentPlugins = ref<Plugin[]>([])

// 是否加载中
const loading = ref(false)

// 各插件的图标加载状态
const pluginIconLoadError = ref<Record<string, boolean>>({})

// 各插件的背景颜色
const pluginBackgroundColors = ref<Record<string, string>>({})

// 上滑关闭配置常量
const SWIPE_CONFIG = {
  START_THRESHOLD: 10, // 开始检测上滑的最小距离
  CLOSE_THRESHOLD: 100, // 触发关闭的距离
  MAX_DRAG_DISTANCE: 1000, // 最大拖拽距离
  VELOCITY_THRESHOLD: 0.8, // 快速滑动速度阈值 (px/ms)
}

// 上滑关闭相关状态
const isDraggingToClose = ref(false)
const dragOffset = ref(0)
const startY = ref(0)
const lastY = ref(0)
const lastTime = ref(0)
const velocity = ref(0)
const startedFromBottomArea = ref(false)

// 插件弹窗相关状态
const showPluginDataDialog = ref(false)
const currentPlugin = ref<Plugin | null>(null)

// 计算显示状态
const isVisible = computed(() => {
  return props.visible
})

// 处理插件图标加载错误
function handleIconError(plugin: Plugin) {
  pluginIconLoadError.value[plugin.id] = true
}

// 处理插件图标加载完成
async function handleIconLoaded(src: string | undefined, plugin: Plugin) {
  if (!src) return

  try {
    // 创建一个临时的img元素来获取图片数据
    const img = new Image()
    img.crossOrigin = 'anonymous'
    img.onload = async () => {
      try {
        // 从图片中提取背景色
        const backgroundColor = await getDominantColor(img)
        pluginBackgroundColors.value[plugin.id] = backgroundColor
      } catch (error) {
        // 如果提取失败，使用默认颜色
        pluginBackgroundColors.value[plugin.id] = '#28A9E1'
      }
    }
    img.onerror = () => {
      // 如果加载失败，使用默认颜色
      pluginBackgroundColors.value[plugin.id] = '#28A9E1'
    }
    img.src = src
  } catch (error) {
    // 如果提取失败，使用默认颜色
    pluginBackgroundColors.value[plugin.id] = '#28A9E1'
  }
}

// 获取插件背景颜色
function getPluginBackgroundColor(plugin: Plugin): string {
  return pluginBackgroundColors.value[plugin.id] || '#28A9E1'
}

// 计算整个组件的transform（包含拖动偏移）
const componentTransform = computed(() => {
  let baseTransform = ''
  if (props.visible) {
    baseTransform = 'translateY(0)'
  } else {
    baseTransform = 'translateY(-100%)'
  }

  // 如果正在拖动关闭，添加拖动偏移（向上拖拽为负值，让面板向上移动）
  if (isDraggingToClose.value) {
    return `${baseTransform} translateY(-${dragOffset.value}px)`
  }

  return baseTransform
})

// 计算组件透明度
const componentOpacity = computed(() => {
  return props.visible ? 1 : 0
})

// 计算插件图标路径
function getPluginIcon(plugin: Plugin): string {
  if (!plugin.plugin_icon) return getLogoUrl('plugin')
  if (pluginIconLoadError.value[plugin.id]) return getLogoUrl('plugin')

  // 如果是网络图片则使用代理后返回
  if (plugin?.plugin_icon?.startsWith('http'))
    return `${import.meta.env.VITE_API_BASE_URL}system/img/1?imgurl=${encodeURIComponent(
      plugin?.plugin_icon,
    )}&cache=true`

  return `./plugin_icon/${plugin?.plugin_icon}`
}

// 获取有详情页面的插件
async function fetchPluginsWithPage() {
  if (loading.value) return

  try {
    loading.value = true
    const allPlugins: Plugin[] = await api.get('plugin/', {
      params: {
        state: 'installed',
      },
    })

    // 只保留有详情页面且已启用的插件
    pluginsWithPage.value = allPlugins
      .filter(plugin => plugin.has_page)
      .sort((a, b) => {
        // 按插件名称排序
        return (a.plugin_name || '').localeCompare(b.plugin_name || '')
      })
  } catch (error) {
    console.error('获取插件列表失败:', error)
  } finally {
    loading.value = false
  }
}

// 加载最近访问的插件
function loadRecentPlugins() {
  recentPlugins.value = getRecentPlugins()
}

// 点击插件
function handlePluginClick(plugin: Plugin) {
  // 添加到最近访问列表
  addRecentPlugin(plugin)

  // 更新最近访问列表显示
  loadRecentPlugins()

  emit('plugin-click', plugin)

  // 设置当前插件并显示数据弹窗
  currentPlugin.value = plugin
  showPluginDataDialog.value = true
}

// 关闭面板
function handleClose() {
  emit('close')
}

// 关闭插件数据弹窗
function handleClosePluginDataDialog() {
  showPluginDataDialog.value = false
  currentPlugin.value = null
}

// 管理滚动状态
function manageScrollLock() {
  if (isVisible.value) {
    // 使用 nextTick 确保 DOM 已经更新
    nextTick(() => {
      // 先恢复之前的锁定状态，避免重复锁定
      const scrollableElement = document.querySelector('.all-plugins-grid')
      if (scrollableElement) {
        // 确保元素存在且可见
        if ((scrollableElement as HTMLElement).offsetHeight > 0) {
          disableBodyScroll(scrollableElement as HTMLElement)
        }
      }
    })
  } else {
    // 恢复背景滚动
    const scrollableElement = document.querySelector('.all-plugins-grid')
    if (scrollableElement) {
      enableBodyScroll(scrollableElement as HTMLElement)
    }
  }
}

// 监听可见性变化，加载数据
watch(
  () => isVisible.value,
  visible => {
    if (visible) {
      fetchPluginsWithPage()
      loadRecentPlugins()
      manageScrollLock()
    } else {
      manageScrollLock()
    }
  },
  { immediate: true },
)

onMounted(() => {
  if (isVisible.value) {
    fetchPluginsWithPage()
    loadRecentPlugins()
    manageScrollLock()
  }
})

// 组件卸载时确保恢复背景滚动
onUnmounted(() => {
  const scrollableElement = document.querySelector('.all-plugins-grid')
  if (scrollableElement) {
    enableBodyScroll(scrollableElement as HTMLElement)
  }
})

// 处理触摸开始
function handleTouchStart(event: TouchEvent) {
  if (!props.visible) return

  const touch = event.touches[0]
  if (!touch) return

  // 检查是否从 bottom-drag-area 开始触摸
  const target = event.target as HTMLElement
  startedFromBottomArea.value = !!target.closest('.bottom-drag-area')

  // 如果触摸发生在插件网格内，不处理拖拽关闭
  if (target.closest('.plugin-grid')) {
    startedFromBottomArea.value = false
    return
  }

  startY.value = touch.clientY
  lastY.value = touch.clientY
  lastTime.value = Date.now()
  velocity.value = 0

  // 重置拖拽状态
  isDraggingToClose.value = false
  dragOffset.value = 0
}

// 处理触摸移动
function handleTouchMove(event: TouchEvent) {
  if (!props.visible) return

  const touch = event.touches[0]
  if (!touch) return

  // 只有从 bottom-drag-area 开始的触摸才处理上滑关闭
  if (!startedFromBottomArea.value) return

  // 检查当前触摸是否在插件网格内，如果是则不处理拖拽关闭
  const target = event.target as HTMLElement
  if (target.closest('.plugin-grid')) {
    return
  }

  const currentY = touch.clientY
  const currentTime = Date.now()
  const deltaY = startY.value - currentY // 向上为正值
  const timeDelta = currentTime - lastTime.value

  // 计算速度
  if (timeDelta > 0) {
    const moveDistance = lastY.value - currentY
    velocity.value = moveDistance / timeDelta
  }

  // 如果已经开始拖拽，继续拖拽
  if (isDraggingToClose.value) {
    if (deltaY >= 0) {
      // 向上拖拽，更新偏移量
      dragOffset.value = Math.min(deltaY, SWIPE_CONFIG.MAX_DRAG_DISTANCE)
      event.preventDefault()
    } else {
      // 向下拖拽，停止拖拽
      isDraggingToClose.value = false
      dragOffset.value = 0
    }
  } else {
    // 还没开始拖拽，检查是否应该开始
    if (deltaY > SWIPE_CONFIG.START_THRESHOLD) {
      isDraggingToClose.value = true
      dragOffset.value = Math.min(deltaY, SWIPE_CONFIG.MAX_DRAG_DISTANCE)
      event.preventDefault()
    }
  }

  lastY.value = currentY
  lastTime.value = currentTime
}

// 处理触摸结束
function handleTouchEnd() {
  if (!props.visible) return

  // 只有从 bottom-drag-area 开始的触摸才处理上滑关闭
  if (!startedFromBottomArea.value) return

  if (isDraggingToClose.value) {
    // 判断是否应该关闭：距离超过阈值或者快速上滑
    const shouldClose =
      dragOffset.value >= SWIPE_CONFIG.CLOSE_THRESHOLD || velocity.value >= SWIPE_CONFIG.VELOCITY_THRESHOLD

    if (shouldClose) {
      emit('close')
    }

    // 重置拖拽状态
    isDraggingToClose.value = false
    dragOffset.value = 0
  }

  // 重置所有状态
  startY.value = 0
  lastY.value = 0
  velocity.value = 0
  startedFromBottomArea.value = false
}

// 点击底部空白区域关闭
function handleBackdropClick(event: MouseEvent) {
  const target = event.target as HTMLElement
  // 点击根容器或底部提示区域时关闭
  if (
    target.classList.contains('plugin-quick-access') ||
    target.classList.contains('footer-hint') ||
    target.classList.contains('hint-text') ||
    target.classList.contains('bottom-drag-area')
  ) {
    emit('close')
  }
}
</script>

<template>
  <VCard
    :ripple="false"
    class="plugin-quick-access"
    :class="{ 'visible': isVisible }"
    :style="{
      opacity: componentOpacity,
      transform: componentTransform,
      transition: isDraggingToClose ? 'none' : 'all 0.6s cubic-bezier(0.4, 0, 0.2, 1)',
    }"
    @click="handleBackdropClick"
    @touchstart="handleTouchStart"
    @touchmove="handleTouchMove"
    @touchend="handleTouchEnd"
  >
    <!-- 顶部指示器 -->
    <div class="top-indicator"></div>

    <!-- 标题栏 -->
    <div class="header">
      <div class="header-title">{{ t('plugin.quickAccess') }}</div>
      <VBtn icon variant="text" @click="handleClose" class="close-btn">
        <VIcon icon="mdi-close" />
      </VBtn>
    </div>

    <!-- 插件网格 -->
    <div class="plugin-grid">
      <!-- 加载状态 -->
      <LoadingBanner v-if="loading" />

      <!-- 最近访问 -->
      <template v-else>
        <div class="section-header">
          <div class="section-title">{{ t('plugin.recentlyUsed') }}</div>
        </div>

        <div v-if="recentPlugins.length > 0" class="recent-plugins-row">
          <div
            v-for="plugin in recentPlugins"
            :key="`recent-${plugin.id}`"
            class="plugin-item"
            @click="handlePluginClick(plugin)"
          >
            <VBadge dot :color="plugin.state ? 'success' : 'secondary'" location="top end">
              <div
                class="plugin-icon"
                :style="{
                  background: `${getPluginBackgroundColor(plugin)}`,
                }"
              >
                <VImg
                  :src="getPluginIcon(plugin)"
                  :alt="plugin.plugin_name"
                  cover
                  @error="handleIconError(plugin)"
                  @load="src => handleIconLoaded(src, plugin)"
                  class="rounded-lg"
                />
              </div>
            </VBadge>
            <div class="plugin-name">{{ plugin.plugin_name }}</div>
          </div>
        </div>

        <!-- 没有最近访问时显示"无" -->
        <div v-else class="no-recent-plugins">
          <VIcon icon="mdi-puzzle-outline" size="24" color="grey" />
        </div>

        <!-- 所有插件 -->
        <div v-if="pluginsWithPage.length > 0" class="section-header with-margin">
          <div class="section-title">{{ t('plugin.allPlugins') }}</div>
        </div>

        <div v-if="pluginsWithPage.length > 0" class="all-plugins-container">
          <div class="all-plugins-grid">
            <div
              v-for="plugin in pluginsWithPage"
              :key="plugin.id"
              class="plugin-item"
              @click="handlePluginClick(plugin)"
            >
              <VBadge
                dot
                :color="plugin.state ? 'success' : 'secondary'"
                location="top end"
                :offset-x="-1"
                :offset-y="-1"
              >
                <div
                  class="plugin-icon"
                  :style="{
                    background: `${getPluginBackgroundColor(plugin)}`,
                  }"
                >
                  <VImg
                    :src="getPluginIcon(plugin)"
                    :alt="plugin.plugin_name"
                    cover
                    @load="src => handleIconLoaded(src, plugin)"
                    @error="handleIconError(plugin)"
                    class="rounded-lg"
                  />
                </div>
              </VBadge>
              <div class="plugin-name">{{ plugin.plugin_name }}</div>
            </div>
          </div>
        </div>
        <!-- 空状态（只有在没有插件时显示） -->
        <div v-else-if="pluginsWithPage.length === 0" class="empty-state">
          <VIcon icon="mdi-puzzle-outline" size="48" color="grey" />
          <div class="empty-text">{{ t('plugin.noPluginsWithPage') }}</div>
        </div>
      </template>
    </div>

    <!-- 底部拖动区域 -->
    <div class="bottom-drag-area" @click="handleBackdropClick">
      <!-- 底部指示器 -->
      <div class="bottom-indicator">
        <div
          class="indicator-bar bottom"
          :class="{ 'dragging': isDraggingToClose }"
          :style="{
            transform: isDraggingToClose
              ? `scaleX(${Math.min(dragOffset / SWIPE_CONFIG.CLOSE_THRESHOLD, 1.5)})`
              : 'scaleX(1)',
            background: isDraggingToClose
              ? dragOffset >= SWIPE_CONFIG.CLOSE_THRESHOLD
                ? 'rgba(var(--v-theme-success), 0.8)'
                : 'rgba(var(--v-theme-primary), 0.8)'
              : 'rgba(var(--v-theme-on-surface), 0.12)',
          }"
        ></div>
      </div>
    </div>
  </VCard>

  <!-- 插件数据弹窗 -->
  <PluginDataDialog
    v-if="showPluginDataDialog && currentPlugin"
    v-model="showPluginDataDialog"
    :plugin="currentPlugin"
    :show_switch="false"
    @close="handleClosePluginDataDialog"
  />
</template>

<style lang="scss" scoped>
.plugin-quick-access {
  position: fixed;
  z-index: 9999;
  display: flex;
  overflow: hidden;
  flex-direction: column;
  backdrop-filter: blur(32px);
  background: rgba(var(--v-theme-surface), 0.95);
  block-size: 100vh;
  block-size: 100dvh;
  inset-block-start: 0;
  inset-inline: 0;
  opacity: 0;
  padding-block: env(safe-area-inset-top) env(safe-area-inset-bottom);
  padding-inline: env(safe-area-inset-left) env(safe-area-inset-right);
  pointer-events: none;
  transform: translateY(-100%);
  transition: all 1s cubic-bezier(0.4, 0, 0.2, 1);

  &.visible {
    opacity: 1;
    pointer-events: auto;
    transform: translateY(0);
  }
}

.top-indicator {
  display: flex;
  justify-content: center;
  padding-block: 12px 8px;
  padding-inline: 0;
}

// 底部相关样式
.bottom-indicator {
  display: flex;
  justify-content: center;
  padding-block: 8px 12px;
  padding-inline: 0;

  .indicator-bar.bottom {
    border-radius: 2px;
    background: rgba(var(--v-theme-on-surface), 0.12);
    block-size: 4px;
    inline-size: 30vw;
    transform-origin: center;
    transition: all 0.2s ease;
  }
}

.header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-block-end: 1px solid rgba(var(--v-theme-on-surface), 0.08);
  padding-block: 0 16px;
  padding-inline: 20px;

  .header-title {
    color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity));
    font-size: 20px;
    font-weight: 600;
  }

  .close-btn {
    opacity: 0.6;

    &:hover {
      background: rgba(var(--v-theme-on-surface), 0.04);
      opacity: 1;
    }
  }
}

.plugin-grid {
  display: flex;
  overflow: hidden auto;
  flex: 1;
  flex-direction: column;
  gap: 16px;
  max-block-size: calc(100vh - 200px); // 确保有最大高度限制
  min-block-size: 0;
  -webkit-overflow-scrolling: touch;
  -ms-overflow-style: none; // IE/Edge
  overscroll-behavior: contain;
  padding-block: 24px;
  padding-inline: 20px;

  // 隐藏滚动条
  scrollbar-width: none; // Firefox
  touch-action: pan-y;
  will-change: scroll-position;

  &::-webkit-scrollbar {
    display: none; // WebKit 浏览器
  }
}

.section-header {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-inline: 0;

  .section-title {
    color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity));
    font-size: 16px;
    font-weight: 600;
    white-space: nowrap;
  }
}

.no-recent-plugins {
  display: flex;
  align-items: center;
  justify-content: center;
  padding-inline: 0;
}

.recent-plugins-row {
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
  padding-block: 0;
  padding-inline: 0;
}

.all-plugins-container {
  display: flex;
  overflow: hidden;
  flex: 1;
  flex-direction: column;
  min-block-size: 0;
}

.all-plugins-grid {
  display: grid;
  gap: 4px;
  grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
  max-block-size: 100%;
  -webkit-overflow-scrolling: touch;
  -ms-overflow-style: none; // IE/Edge
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-block: 8px;
  padding-inline: 0;

  // 隐藏滚动条
  scrollbar-width: none; // Firefox
  touch-action: pan-y;
  will-change: scroll-position;

  &::-webkit-scrollbar {
    display: none; // WebKit 浏览器
  }
}

.plugin-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
  block-size: 120px;
  cursor: pointer;
  gap: 4px;
  transition: all 0.2s ease;

  &:hover {
    background: rgba(var(--v-theme-on-surface), 0.04);
    transform: translateY(-2px);
  }

  &:active {
    background: rgba(var(--v-theme-on-surface), 0.08);
    transform: translateY(0);
  }
}

.plugin-icon {
  position: relative;
  display: flex;
  overflow: hidden;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  padding: 4px;
  border-radius: 16px;
  block-size: 64px;
  inline-size: 64px;
  transition: all 0.2s ease;

  .plugin-item:hover & {
    transform: scale(1.02);
  }
}

.plugin-name {
  display: -webkit-box;
  overflow: hidden;
  flex-shrink: 0;
  -webkit-box-orient: vertical;
  color: rgba(var(--v-theme-on-surface), var(--v-high-emphasis-opacity));
  font-size: 12px;
  font-weight: 500;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  line-height: 1.2;
  max-block-size: 2.4em;
  text-align: center;
  word-break: break-all;
}

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  grid-column: 1 / -1;
  padding-block: 40px;
  padding-inline: 0;

  .empty-text {
    color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
    font-size: 14px;
  }
}

.bottom-drag-area {
  display: flex;
  flex-direction: column;
  align-items: center;
  cursor: pointer;
  padding-block: 8px 0;
  padding-inline: 20px;
}

@media (hover: none) and (pointer: coarse) {
  .plugin-item:hover {
    background: transparent;
    transform: none;
  }

  .plugin-item:active {
    background: rgba(var(--v-theme-on-surface), 0.08);
  }
}

// 深色模式适配
html[data-theme='dark'] .plugin-quick-access {
  background: rgba(var(--v-theme-surface), 0.9);
}
</style>
