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

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

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

import { ElEmpty } from 'element-plus';

import WidgetRenderer from './components/WidgetRenderer.vue';

const props = defineProps<{
  config: DashboardConfig | string;
}>();

const dashboardConfig = ref<DashboardConfig | null>(null);

const parseConfig = () => {
  if (!props.config) {
    dashboardConfig.value = null;
    return;
  }

  if (typeof props.config === 'string') {
    try {
      dashboardConfig.value = JSON.parse(props.config);
    } catch {
      console.error('Invalid dashboard config JSON');
      dashboardConfig.value = null;
    }
  } else {
    dashboardConfig.value = props.config;
  }
};

onMounted(parseConfig);
watch(() => props.config, parseConfig);

const layout = computed(() => {
  if (!dashboardConfig.value) return [];
  const columns = dashboardConfig.value.columns || 12;
  return dashboardConfig.value.widgets.map((w) => ({
    ...w,
    columnEnd: `span ${Math.min(w.w, columns)}`,
    columnStart: Math.max(1, w.x + 1),
    i: w.i,
    minHeight: `${w.h * dashboardConfig.value!.rowHeight}px`,
    rowEnd: `span ${w.h}`,
    rowStart: Math.max(1, w.y + 1),
  }));
});

const getWidget = (i: string) => {
  if (!dashboardConfig.value) return null;
  return dashboardConfig.value.widgets.find((w) => w.i === i);
};

const getAnimationDelay = (i: string) => {
  if (!dashboardConfig.value) return 0;
  const index = dashboardConfig.value.widgets.findIndex((w) => w.i === i);
  return index * 80;
};

const outerMarginStyle = computed(() => {
  const config = dashboardConfig.value;
  if (!config || config.showOuterMargin !== false) return {};
  const margin = config.margin || [12, 12];
  return {
    marginLeft: `-${margin[0]}px`,
    marginRight: `-${margin[0]}px`,
    marginTop: `-${margin[1]}px`,
    width: `calc(100% + ${margin[0] * 2}px)`,
  };
});

const gridStyle = computed(() => {
  const config = dashboardConfig.value;
  if (!config) return {};
  const margin = config.margin || [12, 12];
  return {
    ...outerMarginStyle.value,
    display: 'grid',
    gap: `${margin[1]}px ${margin[0]}px`,
    gridAutoFlow: 'dense',
    gridAutoRows: `${config.rowHeight}px`,
    gridTemplateColumns: `repeat(${config.columns || 12}, minmax(0, 1fr))`,
  };
});
</script>

<template>
  <div
    class="dashboard-renderer h-full"
    :style="
      dashboardConfig?.backgroundColor?.includes('gradient')
        ? { background: dashboardConfig.backgroundColor }
        : { backgroundColor: dashboardConfig?.backgroundColor || '' }
    "
  >
    <div v-if="dashboardConfig && layout.length > 0">
      <div :style="gridStyle">
        <div
          v-for="item in layout"
          :key="item.i"
          class="dashboard-widget"
          :style="{
            gridColumnEnd: item.columnEnd,
            gridColumnStart: item.columnStart,
            gridRowEnd: item.rowEnd,
            gridRowStart: item.rowStart,
            minHeight: item.minHeight,
          }"
        >
          <WidgetRenderer
            v-if="getWidget(item.i)"
            :widget="getWidget(item.i)!"
            :is-design-mode="false"
            :animation-delay="getAnimationDelay(item.i)"
          />
        </div>
      </div>
    </div>

    <ElEmpty
      v-else
      :description="$t('dashboard-design.noConfigTip')"
      class="py-20"
    />
  </div>
</template>

<style scoped>
.dashboard-renderer {
  background-color: var(--el-bg-color-page);
}

.dashboard-widget {
  overflow: hidden;
  background: var(--el-bg-color);
  border-radius: 8px;
  box-shadow: 0 1px 3px rgb(0 0 0 / 10%);
}
</style>
