<script setup>
import { computed, useSlots, Fragment, provide } from "vue";
import { useNamespace } from "@yh-ui/hooks";
import { useComponentTheme } from "@yh-ui/theme";
import { descriptionsProps, descriptionsKey } from "./descriptions";
defineOptions({
  name: "YhDescriptions"
});
const props = defineProps(descriptionsProps);
const slots = useSlots();
const ns = useNamespace("descriptions");
const { themeStyle } = useComponentTheme(
  "descriptions",
  computed(() => props.themeOverrides)
);
provide(descriptionsKey, { props });
const getFlattenChildren = (nodes) => {
  const result = [];
  nodes.forEach((node) => {
    if (node.type === Fragment && Array.isArray(node.children)) {
      result.push(...getFlattenChildren(node.children));
    } else if (node.type && typeof node.type === "object" && "name" in node.type && node.type.name === "YhDescriptionsItem") {
      result.push(node);
    }
  });
  return result;
};
const rows = computed(() => {
  const children = slots.default ? getFlattenChildren(slots.default()) : [];
  const rows2 = [];
  let tempRow = [];
  let occupiedSpan = 0;
  const totalColumn = Number(props.column);
  children.forEach((node, index) => {
    const itemProps = { ...node.props || {} };
    let span = Number(itemProps.span || 1);
    if (occupiedSpan + span > totalColumn) {
      if (tempRow.length > 0) {
        const lastItem = tempRow[tempRow.length - 1];
        lastItem.actualSpan += totalColumn - occupiedSpan;
        rows2.push(tempRow);
      }
      tempRow = [];
      occupiedSpan = 0;
    }
    const item = {
      props: itemProps,
      slots: node.children || {},
      actualSpan: span
    };
    tempRow.push(item);
    occupiedSpan += span;
    if (index === children.length - 1) {
      item.actualSpan += totalColumn - occupiedSpan;
      rows2.push(tempRow);
    }
  });
  return rows2;
});
const getStyle = (itemProps, type) => {
  const style = { ...type === "label" ? props.labelStyle : props.contentStyle };
  const itemStyle = type === "label" ? itemProps.labelStyle : itemProps.contentStyle;
  Object.assign(style, itemStyle || {});
  if (type === "label") {
    if (itemProps.width)
      style.width = typeof itemProps.width === "number" ? `${itemProps.width}px` : itemProps.width;
    if (itemProps.minWidth)
      style.minWidth = typeof itemProps.minWidth === "number" ? `${itemProps.minWidth}px` : itemProps.minWidth;
    style.textAlign = itemProps.labelAlign || itemProps.align || "left";
  } else {
    style.textAlign = itemProps.align || "left";
  }
  return style;
};
const getClassName = (itemProps, type) => {
  const classes = [];
  if (type === "label" && props.labelClassName) {
    classes.push(props.labelClassName);
  }
  if (type === "content" && props.contentClassName) {
    classes.push(props.contentClassName);
  }
  if (type === "label" && itemProps.labelClassName) {
    classes.push(itemProps.labelClassName);
  }
  if (type === "content" && itemProps.className) {
    classes.push(itemProps.className);
  }
  return classes;
};
const descriptionsClasses = computed(() => [
  ns.b(),
  ns.m(props.size),
  ns.is("bordered", props.border),
  ns.is("vertical", props.direction === "vertical")
]);
</script>

<template>
  <div :class="descriptionsClasses" :style="themeStyle">
    <div v-if="title || extra || $slots.title || $slots.extra" :class="ns.e('header')">
      <div :class="ns.e('title')">
        <slot name="title">{{ title }}</slot>
      </div>
      <div :class="ns.e('extra')">
        <slot name="extra">{{ extra }}</slot>
      </div>
    </div>

    <div :class="ns.e('body')">
      <table :class="[ns.e('table'), ns.is('bordered', border)]">
        <tbody>
          <template v-for="(row, rowIndex) in rows" :key="rowIndex">
            <!-- 横向布局 -->
            <tr v-if="direction === 'horizontal'" :class="ns.e('row')">
              <template v-for="(item, cellIndex) in row" :key="cellIndex">
                <th
                  :class="[ns.e('label'), ...getClassName(item.props, 'label')]"
                  :style="getStyle(item.props, 'label')"
                >
                  <component :is="item.slots.label" v-if="item.slots.label" />
                  <template v-else>{{ item.props.label }}</template>
                  <span v-if="colon && !border && (item.props.label || item.slots.label)">:</span>
                </th>
                <td
                  :class="[ns.e('content'), ...getClassName(item.props, 'content')]"
                  :style="getStyle(item.props, 'content')"
                  :colspan="item.actualSpan * 2 - 1 > 1 ? item.actualSpan * 2 - 1 : void 0"
                >
                  <component :is="item.slots.default" v-if="item.slots.default" />
                </td>
              </template>
            </tr>
            <!-- 垂直布局 -->
            <template v-else>
              <tr :class="ns.e('row')">
                <th
                  v-for="(item, cellIndex) in row"
                  :key="cellIndex"
                  :class="[ns.e('label'), ...getClassName(item.props, 'label')]"
                  :style="getStyle(item.props, 'label')"
                  :colspan="item.actualSpan"
                >
                  <component :is="item.slots.label" v-if="item.slots.label" />
                  <template v-else>{{ item.props.label }}</template>
                </th>
              </tr>
              <tr :class="ns.e('row')">
                <td
                  v-for="(item, cellIndex) in row"
                  :key="cellIndex"
                  :class="[ns.e('content'), ...getClassName(item.props, 'content')]"
                  :style="getStyle(item.props, 'content')"
                  :colspan="item.actualSpan"
                >
                  <component :is="item.slots.default" v-if="item.slots.default" />
                </td>
              </tr>
            </template>
          </template>
        </tbody>
      </table>
    </div>
  </div>
</template>

<style>
@charset "UTF-8";
/**
 * YH-UI Sass Variables
 * 原具体的 CSS 变量输出规则 (:root, html.dark 等) 已移至 root.scss，以防止各组件样式编译时产生重复的全局变量 CSS 冗余。
 */
.yh-descriptions {
  --yh-descriptions-item-font-size: var(--yh-component-size-default-font, 14px);
  --yh-descriptions-padding: var(--yh-component-size-default-padding, 16px);
  --yh-descriptions-border-color: var(--yh-border-color-lighter, #ebeef5);
  box-sizing: border-box;
  color: var(--yh-text-color-primary, #303133);
}
.yh-descriptions--large {
  --yh-descriptions-item-font-size: var(--yh-component-size-large-font);
  --yh-descriptions-padding: var(--yh-component-size-large-padding);
}

.yh-descriptions--small {
  --yh-descriptions-item-font-size: var(--yh-component-size-small-font);
  --yh-descriptions-padding: var(--yh-component-size-small-padding);
}

.yh-descriptions__header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: var(--yh-spacing-md, 16px);
}

.yh-descriptions__title {
  color: var(--yh-text-color-primary);
  font-weight: 700;
  font-size: var(--yh-font-size-md, 16px);
}

.yh-descriptions__body {
  background-color: transparent;
  border-radius: 0;
}

.yh-descriptions__table {
  width: 100%;
  margin: 0;
  padding: 0;
  border-radius: 0;
  table-layout: auto;
  border-collapse: collapse;
  border-spacing: 0;
}
.yh-descriptions__table.is-fixed {
  table-layout: fixed;
}

.yh-descriptions__label {
  box-sizing: border-box;
  color: var(--yh-text-color-regular);
  font-weight: 400;
  font-size: var(--yh-descriptions-item-font-size);
  padding: var(--yh-descriptions-padding);
  text-align: left;
  vertical-align: middle;
  background-color: transparent;
  border-radius: 0;
  white-space: nowrap;
}

.yh-descriptions__content {
  box-sizing: border-box;
  color: var(--yh-text-color-primary);
  font-size: var(--yh-descriptions-item-font-size);
  padding: var(--yh-descriptions-padding);
  vertical-align: middle;
  word-break: normal;
  overflow-wrap: break-word;
  border-radius: 0;
}

.yh-descriptions:not(.is-bordered) .yh-descriptions__label {
  padding-left: 0;
}

.yh-descriptions.is-bordered .yh-descriptions__table {
  border: 1px solid var(--yh-descriptions-border-color);
}

.yh-descriptions.is-bordered .yh-descriptions__label, .yh-descriptions.is-bordered .yh-descriptions__content {
  border: 1px solid var(--yh-descriptions-border-color);
}

.yh-descriptions.is-bordered .yh-descriptions__label {
  background-color: var(--yh-fill-color-light, #f5f7fa);
  font-weight: 700;
  color: var(--yh-text-color-primary);
  width: 150px;
}

.yh-descriptions.is-bordered .yh-descriptions__content {
  background-color: var(--yh-fill-color-blank, #ffffff);
}

.yh-descriptions.is-vertical .yh-descriptions__label {
  width: auto;
  padding-left: var(--yh-descriptions-padding);
}
</style>
