<script setup lang="ts">
import type {
  DashboardWidget,
  WidgetStyle,
} from '../types';

import {
  computed,
  defineAsyncComponent,
  onMounted,
  onUnmounted,
  ref,
  watch,
} from 'vue';

import { Loader2 } from '@vben/icons';
import { $t } from '@vben/locales';

import { useDashboardRuntime } from '../runtime';
import { createRefreshTimer, fetchWidgetData } from '../utils/dataFetcher';

const props = defineProps<{
  animationDelay?: number; // 入场动画延迟（毫秒）
  isDesignMode?: boolean;
  widget: DashboardWidget;
}>();

// 入场动画状态
const isEntered = ref(false);
// 数据更新动画状态
const isUpdating = ref(false);

// 组件映射
const widgetComponents: Record<
  string,
  ReturnType<typeof defineAsyncComponent>
> = {
  'announcement-list': defineAsyncComponent(
    () => import('./widgets/AnnouncementList.vue'),
  ),
  'approval-center': defineAsyncComponent(
    () => import('./widgets/ApprovalCenter.vue'),
  ),
  'my-apps': defineAsyncComponent(() => import('./widgets/MyApps.vue')),
  'notice-list': defineAsyncComponent(() => import('./widgets/NoticeList.vue')),
  'quick-links': defineAsyncComponent(() => import('./widgets/QuickLinks.vue')),
  'server-monitor': defineAsyncComponent(
    () => import('./widgets/ServerMonitor.vue'),
  ),
  weather: defineAsyncComponent(() => import('./widgets/WeatherWidget.vue')),
  'welcome-card': defineAsyncComponent(
    () => import('./widgets/WelcomeCard.vue'),
  ),
};

const defaultWidgetStyle: WidgetStyle = {
  backgroundColor: '',
  borderWidth: 0,
  borderColor: '',
  borderStyle: 'solid',
  borderRadius: 8,
  shadowEnabled: true,
  shadowColor: 'rgba(0, 0, 0, 0.1)',
  shadowBlur: 4,
  shadowOffsetX: 0,
  shadowOffsetY: 1,
  padding: 16,
  titleShow: true,
  titleFontSize: 14,
  titleColor: '',
  titleAlign: 'left',
  titleFontWeight: 'normal',
};

const { globalParams, globalParamsVersion } = useDashboardRuntime();

const currentComponent = computed(() => {
  return widgetComponents[props.widget.type];
});

// 从 paramBindings 解析出实际参数值
function resolveParams(): Record<string, any> | undefined {
  const bindings = props.widget.dataSource?.paramBindings;
  if (!bindings || bindings.length === 0) return undefined;
  const params: Record<string, any> = {};
  for (const b of bindings) {
    if (b.paramName && b.globalKey) {
      const val = globalParams.value[b.globalKey];
      if (val !== undefined && val !== '') {
        params[b.paramName] = val;
      }
    }
  }
  return Object.keys(params).length > 0 ? params : undefined;
}

// 动态数据
const dynamicProps = ref<Record<string, any>>({});
const isLoading = ref(false);
const hasError = ref(false);

// 合并后的 widget（静态 props + 动态 props）
const mergedWidget = computed(() => {
  return {
    ...props.widget,
    props: {
      ...props.widget.props,
      ...dynamicProps.value,
    },
  };
});

// 计算样式（只应用容器级别的样式，不影响组件内部）
const widgetStyle = computed(() => {
  const style = { ...defaultWidgetStyle, ...props.widget.style };
  const css: Record<string, string> = {};

  // 背景（默认使用主题背景色，支持渐变色）
  const bgValue = style.backgroundColor || 'var(--el-bg-color)';
  if (bgValue.includes('gradient')) {
    css.background = bgValue;
  } else {
    css.backgroundColor = bgValue;
  }

  // 边框
  if (style.borderWidth && style.borderWidth > 0) {
    css.borderWidth = `${style.borderWidth}px`;
    css.borderStyle = style.borderStyle || 'solid';
    css.borderColor = style.borderColor || 'var(--el-border-color)';
  }

  // 圆角
  if (style.borderRadius !== undefined) {
    css.borderRadius = `${style.borderRadius}px`;
  }

  // 阴影
  if (style.shadowEnabled) {
    const color = style.shadowColor || 'rgba(0, 0, 0, 0.1)';
    const blur = style.shadowBlur || 4;
    const x = style.shadowOffsetX || 0;
    const y = style.shadowOffsetY || 1;
    css.boxShadow = `${x}px ${y}px ${blur}px ${color}`;
  } else {
    css.boxShadow = 'none';
  }

  return css;
});

// 加载数据
const loadData = async () => {
  if (!props.widget.dataSource || props.widget.dataSource.type === 'static') {
    dynamicProps.value = {};
    return;
  }

  isLoading.value = true;
  hasError.value = false;

  try {
    const params = resolveParams();
    const result = await fetchWidgetData(
      props.widget.dataSource,
      props.widget.props,
      params,
    );

    // 数据更新动画
    if (isEntered.value && Object.keys(dynamicProps.value).length > 0) {
      isUpdating.value = true;
      setTimeout(() => {
        isUpdating.value = false;
      }, 300);
    }

    dynamicProps.value = result.props;
  } catch (error) {
    console.error('[WidgetRenderer] loadData error', error);
    hasError.value = true;
  } finally {
    isLoading.value = false;
  }
};

// 刷新定时器清理函数
let cleanupTimer: (() => void) | null = null;

// 设置刷新定时器
const setupRefreshTimer = () => {
  if (cleanupTimer) {
    cleanupTimer();
    cleanupTimer = null;
  }

  // 支持 api 和 dataSource 类型的自动刷新
  const dsType = props.widget.dataSource?.type;
  if (!props.isDesignMode && (dsType === 'api' || dsType === 'dataSource')) {
    cleanupTimer = createRefreshTimer(props.widget.dataSource, loadData);
  }
};

// 监听数据源变化
watch(
  () => props.widget.dataSource,
  () => {
    loadData();
    setupRefreshTimer();
  },
  { deep: true },
);

// 监听全局筛选参数变化，有 paramBindings 的组件重新加载数据
watch(
  () => globalParamsVersion.value,
  () => {
    if (props.isDesignMode) return;
    const bindings = props.widget.dataSource?.paramBindings;
    if (bindings && bindings.length > 0) {
      loadData();
    }
  },
);

onMounted(() => {
  loadData();
  setupRefreshTimer();

  // 入场动画
  const delay = props.animationDelay || 0;
  setTimeout(() => {
    isEntered.value = true;
  }, delay);
});

onUnmounted(() => {
  if (cleanupTimer) {
    cleanupTimer();
  }
});

// 动画类名
const animationClass = computed(() => {
  return {
    'widget-enter': true,
    'widget-entered': isEntered.value,
    'widget-updating': isUpdating.value,
  };
});
</script>

<template>
  <div
    class="widget-renderer relative h-full w-full overflow-hidden"
    :class="animationClass"
    :style="widgetStyle"
  >
    <!-- 加载状态 -->
    <div
      v-if="isLoading"
      class="absolute inset-0 z-10 flex items-center justify-center bg-white/50"
    >
      <Loader2 class="text-primary h-6 w-6 animate-spin" />
    </div>

    <!-- 错误状态 -->
    <div v-if="hasError && !isLoading" class="absolute right-2 top-2 z-10">
      <span class="text-xs text-red-500">{{
        $t('dashboard-design.loadDataError')
      }}</span>
    </div>

    <!-- 组件内容 -->
    <component
      :is="currentComponent"
      v-if="currentComponent"
      :widget="mergedWidget"
      :is-design-mode="isDesignMode"
    />
    <div
      v-else
      class="flex h-full w-full items-center justify-center text-gray-400"
    >
      {{ $t('dashboard-design.unknownWidget') }}: {{ widget.type }}
    </div>
  </div>
</template>

<style scoped>
@keyframes pulse-update {
  0% {
    transform: scale(1);
  }

  50% {
    box-shadow: 0 0 0 2px var(--el-color-primary-light-5);
    transform: scale(1.02);
  }

  100% {
    transform: scale(1);
  }
}

.widget-enter {
  opacity: 0;
  transform: translateY(20px) scale(0.95);
  transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.widget-entered {
  opacity: 1;
  transform: translateY(0) scale(1);
}

/* 数据更新动画 */
.widget-updating {
  animation: pulse-update 0.3s ease-in-out;
}

/* 入场动画 */
</style>
