<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import { ElButton, ElEmpty, ElIcon, ElPagination, ElTable, ElTableColumn, ElTag } from 'element-plus';
import dayjs from 'dayjs';
import { ArrowDown } from '@element-plus/icons-vue';
import { RDMS_OBJECT_DIRECTION_DICT_CODE } from '@/constants/dict';
import { useDict } from '@/hooks/business/dict';
import CurrentUserRoleTags from '@/components/custom/current-user-role-tags.vue';
import { getProductStatusLabel, getProductStatusTagType } from '../../shared/product-master-data';

defineOptions({ name: 'ProductGroupedTable' });

interface Props {
  /** 当前筛选口径下的全量产品（前端分组 / 收纳 / 假分页都基于它） */
  products: Api.Product.Product[];
  loading?: boolean;
  /** 是否渲染方向小节层（可见方向数 ≥2）；false = 单方向平铺 */
  showDirectionLayer: boolean;
  /** 折叠全部开关（true = 全部方向折叠，仅保留方向头） */
  allCollapsed: boolean;
  /** userId -> 昵称，产品经理列兜底回显 */
  managerLabelMap: Map<string, string>;
}

const props = withDefaults(defineProps<Props>(), { loading: false });

interface Emits {
  (e: 'enter', product: Api.Product.Product): void;
}

const emit = defineEmits<Emits>();

const { getLabel: getDirectionLabel, dictOptions: directionOptions } = useDict(RDMS_OBJECT_DIRECTION_DICT_CODE);

/** 方向内默认直出条数（超出收纳为「还有 X 个」） */
const DEFAULT_TOP_N = 5;
/** 展开后方向内每页条数（超出 1 页才出分页器） */
const PAGE_SIZE = 10;
/** 产品行多列数（名称/编码/经理/我的角色/状态/原因/更新），非产品行整行合并用 */
const COLUMN_COUNT = 7;
/** 产品描述副行长度阈值：超过时展示「详情」入口 */
const PRODUCT_DESC_MAX_LEN = 40;

interface DirectionGroup {
  directionCode: string;
  products: Api.Product.Product[];
}

/** updateTime 后端实际可能为时间戳(number)或字符串，统一转毫秒数比较；缺失/非法兜底 0 */
function updateTimeValue(value: Api.Product.Product['updateTime']) {
  const time = dayjs(value ?? 0).valueOf();

  return Number.isFinite(time) ? time : 0;
}

/** 按方向分组：方向顺序按字典 options，未知方向落最后；组内按最近更新倒序 */
const groups = computed<DirectionGroup[]>(() => {
  const map = new Map<string, Api.Product.Product[]>();

  for (const product of props.products) {
    const code = product.directionCode || '';
    const list = map.get(code);

    if (list) {
      list.push(product);
    } else {
      map.set(code, [product]);
    }
  }

  for (const list of map.values()) {
    list.sort((left, right) => updateTimeValue(right.updateTime) - updateTimeValue(left.updateTime));
  }

  const orderIndex = new Map(directionOptions.value.map((option, index): [string, number] => [option.value, index]));

  return [...map.entries()]
    .map(([directionCode, list]) => ({ directionCode, products: list }))
    .sort((left, right) => {
      const leftOrder = orderIndex.has(left.directionCode)
        ? orderIndex.get(left.directionCode)!
        : Number.MAX_SAFE_INTEGER;
      const rightOrder = orderIndex.has(right.directionCode)
        ? orderIndex.get(right.directionCode)!
        : Number.MAX_SAFE_INTEGER;

      return leftOrder - rightOrder;
    });
});

// === 方向折叠态（折叠 = 隐藏该方向下全部产品；与 top-N 收纳相互独立，对齐项目列表） ===
/** 已折叠方向（按 directionCode） */
const collapsedDirections = ref(new Set<string>());

function collapseAllDirections() {
  return new Set(groups.value.map(group => group.directionCode));
}

function toggleDirection(code: string) {
  const next = new Set(collapsedDirections.value);

  if (next.has(code)) {
    next.delete(code);
  } else {
    next.add(code);
  }

  collapsedDirections.value = next;
}

// === 收纳 / 方向内假分页态（数据刷新即重置） ===
/** 已展开方向（多方向：从前 5 展开到分页态）；单方向恒为展开 */
const expandedDirections = ref(new Set<string>());
/** 方向内当前页码：directionCode -> page（默认 1） */
const directionPages = ref(new Map<string, number>());

watch(
  () => props.products,
  () => {
    expandedDirections.value = new Set();
    directionPages.value = new Map();
    collapsedDirections.value = props.allCollapsed ? collapseAllDirections() : new Set();
  }
);

watch(
  () => props.allCollapsed,
  value => {
    collapsedDirections.value = value ? collapseAllDirections() : new Set();
  }
);

/** 单方向直接进入展开（分页）态，无 5 档收纳 */
function isExpanded(code: string) {
  return !props.showDirectionLayer || expandedDirections.value.has(code);
}

function getPage(code: string) {
  return directionPages.value.get(code) ?? 1;
}

/** 当前方向应渲染的产品：未展开取前 N；展开且 >1 页取当前页切片，否则全量 */
function visibleProducts(group: DirectionGroup) {
  if (!isExpanded(group.directionCode)) {
    return group.products.slice(0, DEFAULT_TOP_N);
  }

  if (group.products.length > PAGE_SIZE) {
    const start = (getPage(group.directionCode) - 1) * PAGE_SIZE;
    return group.products.slice(start, start + PAGE_SIZE);
  }

  return group.products;
}

function toggleExpand(code: string) {
  const next = new Set(expandedDirections.value);

  if (next.has(code)) {
    next.delete(code);
    const pages = new Map(directionPages.value);
    pages.delete(code);
    directionPages.value = pages;
  } else {
    next.add(code);
  }

  expandedDirections.value = next;
}

function changePage(code: string, page: number) {
  const pages = new Map(directionPages.value);
  pages.set(code, page);
  directionPages.value = pages;
}

// === 扁平行模型：分组结构铺平后交给 ElTable，非产品行整行合并单元格 ===
type FlatRowType = 'dir' | 'product' | 'more' | 'pager';

interface FlatRow {
  rowType: FlatRowType;
  key: string;
  group?: DirectionGroup;
  product?: Api.Product.Product;
}

const flatRows = computed<FlatRow[]>(() => {
  const rows: FlatRow[] = [];

  for (const group of groups.value) {
    const code = group.directionCode || 'unknown';
    const total = group.products.length;

    // 方向折叠：仅保留方向头，隐藏其下产品 / 收纳 / 分页行
    const collapsed = props.showDirectionLayer && collapsedDirections.value.has(group.directionCode);

    if (props.showDirectionLayer) {
      rows.push({ rowType: 'dir', key: `dir-${code}`, group });
    }

    if (!collapsed) {
      for (const product of visibleProducts(group)) {
        rows.push({ rowType: 'product', key: `prod-${product.id}`, group, product });
      }

      if (isExpanded(group.directionCode) && total > PAGE_SIZE) {
        rows.push({ rowType: 'pager', key: `pager-${code}`, group });
      }

      // 收起/展开切换行仅多方向出现（单方向无 5 档收纳）
      if (props.showDirectionLayer && total > DEFAULT_TOP_N) {
        rows.push({ rowType: 'more', key: `more-${code}`, group });
      }
    }
  }

  return rows;
});

function getRowKey(row: FlatRow) {
  return row.key;
}

function spanMethod({ row, columnIndex }: { row: FlatRow; columnIndex: number }) {
  if (row.rowType === 'product') {
    return undefined;
  }

  return columnIndex === 0 ? { rowspan: 1, colspan: COLUMN_COUNT } : { rowspan: 0, colspan: 0 };
}

function rowClassName({ row }: { row: FlatRow }) {
  if (row.rowType === 'dir') {
    const collapsed = row.group ? collapsedDirections.value.has(row.group.directionCode) : false;
    return `pg-dir-row${collapsed ? ' is-collapsed' : ''}`;
  }

  if (row.rowType === 'more') {
    return 'pg-more-row';
  }

  if (row.rowType === 'pager') {
    return 'pg-pager-row';
  }

  return 'pg-prod-row';
}

function handleRowClick(row: FlatRow) {
  if (row.rowType === 'dir' && row.group) {
    toggleDirection(row.group.directionCode);
    return;
  }

  if (row.rowType === 'more' && row.group) {
    toggleExpand(row.group.directionCode);
  }
}

// === 回显 ===
function getManagerName(managerUserId?: string | null) {
  if (!managerUserId) {
    return '--';
  }

  return props.managerLabelMap.get(String(managerUserId)) || String(managerUserId);
}

function formatDate(value?: string | null) {
  if (!value) {
    return '--';
  }

  return dayjs(value).format('YYYY-MM-DD');
}

/** 产品描述副行：不再手工截断字符，交给布局省略；完整内容由 title 悬浮展示 */
function truncateDesc(text?: string | null) {
  return (text ?? '').trim();
}

/** 描述是否被截断（放不下）；仅截断时才追加「详情」入口 */
function isDescTruncated(text?: string | null) {
  return (text ?? '').trim().length > PRODUCT_DESC_MAX_LEN;
}
</script>

<template>
  <ElTable
    v-loading="loading"
    class="product-grouped-table"
    height="100%"
    :data="flatRows"
    :row-key="getRowKey"
    :span-method="spanMethod"
    :row-class-name="rowClassName"
    @row-click="handleRowClick"
  >
    <ElTableColumn label="产品名称" min-width="240" align="left">
      <template #default="{ row }">
        <div v-if="row.rowType === 'dir'" class="pg-dir-line">
          <ElIcon class="pg-toggle"><ArrowDown /></ElIcon>
          <span class="pg-dir-chip"></span>
          <span class="pg-dir-name">
            {{ getDirectionLabel(row.group.directionCode, row.group.directionCode || '--') }}
          </span>
          <span class="pg-dir-meta">{{ row.group.products.length }} 个产品</span>
        </div>

        <div v-else-if="row.rowType === 'product'" class="pg-prod-name">
          <span class="pg-prod-icon">
            <icon-material-symbols-package-2 />
          </span>
          <div class="pg-prod-main">
            <ElButton link type="primary" class="pg-prod-link" @click="emit('enter', row.product)">
              {{ row.product.name }}
            </ElButton>
            <div
              v-if="row.product.description?.trim()"
              class="pg-prod-desc"
              :title="row.product.description"
              @click="emit('enter', row.product)"
            >
              <span class="pg-prod-desc__text">{{ truncateDesc(row.product.description) }}</span>
              <span v-if="isDescTruncated(row.product.description)" class="pg-prod-desc__more">详情</span>
            </div>
          </div>
        </div>

        <div v-else-if="row.rowType === 'more'" class="pg-more-line">
          <span class="pg-more-link">
            <ElIcon class="pg-more-icon" :class="{ 'pg-more-icon--up': isExpanded(row.group.directionCode) }">
              <ArrowDown />
            </ElIcon>
            <template v-if="isExpanded(row.group.directionCode)">收起</template>
            <template v-else>还有 {{ row.group.products.length - DEFAULT_TOP_N }} 个，展开查看</template>
          </span>
          <span v-if="!isExpanded(row.group.directionCode)" class="pg-more-hint">
            默认显示前 {{ DEFAULT_TOP_N }} 个，按最近更新排序
          </span>
        </div>

        <div v-else-if="row.rowType === 'pager'" class="pg-pager-line" @click.stop>
          <ElPagination
            small
            layout="total, prev, pager, next"
            :total="row.group.products.length"
            :page-size="PAGE_SIZE"
            :current-page="getPage(row.group.directionCode)"
            @current-change="page => changePage(row.group.directionCode, page)"
          />
        </div>
      </template>
    </ElTableColumn>

    <ElTableColumn label="产品编码" min-width="140" show-overflow-tooltip>
      <template #default="{ row }">
        <template v-if="row.rowType === 'product'">{{ row.product.code || '--' }}</template>
      </template>
    </ElTableColumn>

    <ElTableColumn label="产品经理" width="120">
      <template #default="{ row }">
        <template v-if="row.rowType === 'product'">{{ getManagerName(row.product.managerUserId) }}</template>
      </template>
    </ElTableColumn>

    <ElTableColumn label="我的身份" min-width="140" align="center">
      <template #default="{ row }">
        <CurrentUserRoleTags v-if="row.rowType === 'product'" :roles="row.product.currentUserRoles" />
      </template>
    </ElTableColumn>

    <ElTableColumn label="管理状态" width="120" align="center">
      <template #default="{ row }">
        <ElTag v-if="row.rowType === 'product'" :type="getProductStatusTagType(row.product.statusCode)">
          {{ getProductStatusLabel(row.product.statusCode) }}
        </ElTag>
      </template>
    </ElTableColumn>

    <ElTableColumn label="状态原因" min-width="180" show-overflow-tooltip>
      <template #default="{ row }">
        <template v-if="row.rowType === 'product'">{{ row.product.lastStatusReason?.trim() || '--' }}</template>
      </template>
    </ElTableColumn>

    <ElTableColumn label="最近更新" width="120" align="center">
      <template #default="{ row }">
        <span v-if="row.rowType === 'product'" class="pg-muted">{{ formatDate(row.product.updateTime) }}</span>
      </template>
    </ElTableColumn>

    <template #empty>
      <ElEmpty description="当前筛选条件下暂无产品" />
    </template>
  </ElTable>
</template>

<style lang="scss" scoped>
.product-grouped-table {
  --el-table-row-hover-bg-color: rgb(240 249 255 / 55%);

  // 全局 .el-table .cell { padding: 0 } 把内边距清零了，这里恢复本表的呼吸感
  :deep(td.el-table__cell > .cell),
  :deep(th.el-table__cell > .cell) {
    padding: 0 12px;
  }

  :deep(td.el-table__cell) {
    transition: background-color 0.2s ease;
  }

  // 方向节标题行：无底色、上方留白，像章节标题而不是数据行（可点击折叠）
  :deep(.pg-dir-row > td.el-table__cell) {
    padding: 16px 0 6px;
    background: transparent;
    border-bottom: none;
    cursor: pointer;
  }

  :deep(.pg-prod-row > td.el-table__cell) {
    border-bottom: 1px solid var(--el-border-color-extra-light);
  }

  :deep(.pg-more-row > td.el-table__cell),
  :deep(.pg-pager-row > td.el-table__cell) {
    padding: 6px 0;
    background: transparent;
  }

  :deep(.pg-more-row > td.el-table__cell) {
    cursor: pointer;
  }
}

// === 方向节标题 ===
.pg-toggle {
  flex: none;
  color: var(--el-text-color-placeholder);
  font-size: 13px;
  transition: transform 0.2s ease;
}

.is-collapsed .pg-toggle {
  transform: rotate(-90deg);
}

.pg-dir-line {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.pg-dir-chip {
  flex: none;
  width: 4px;
  height: 14px;
  border-radius: 2px;
  background: rgb(14 165 233 / 85%);
}

.pg-dir-name {
  color: rgb(51 65 85 / 96%);
  font-size: 13px;
  font-weight: 700;
}

.pg-dir-meta {
  color: var(--el-text-color-placeholder);
  font-size: 12px;
}

// === 产品行 ===
.pg-prod-name {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.pg-prod-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 26px;
  height: 26px;
  border-radius: 8px;
  background: rgb(240 249 255 / 96%);
  color: rgb(2 132 199 / 92%);
  font-size: 14px;
}

.pg-prod-main {
  display: flex;
  flex-direction: column;
  // 贴左：避免 ElButton(link) 被 stretch 拉满列宽后文字居中
  align-items: flex-start;
  gap: 2px;
  min-width: 0;
}

.pg-prod-link {
  padding: 0;
}

// 描述副行：控长截断 + 末尾「详情」链接，整行可点（进入对象域）
.pg-prod-desc {
  display: flex;
  align-items: center;
  gap: 4px;
  width: 100%;
  min-width: 0;
  cursor: pointer;
}

.pg-prod-desc__text {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  color: var(--el-text-color-secondary);
  font-size: 12px;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.pg-prod-desc__more {
  flex: none;
  color: var(--el-color-primary);
  font-size: 12px;
}

.pg-prod-desc:hover .pg-prod-desc__more {
  text-decoration: underline;
}

.pg-muted {
  color: var(--el-text-color-secondary);
}

// === 收起/展开行 ===
.pg-more-line {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: 34px;
}

.pg-more-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--el-color-primary);
  font-size: 12.5px;
  font-weight: 600;
}

.pg-more-icon {
  font-size: 12px;
  transition: transform 0.2s ease;
}

.pg-more-icon--up {
  transform: rotate(180deg);
}

.pg-more-hint {
  color: var(--el-text-color-placeholder);
  font-size: 12px;
}

// === 方向内分页行 ===
.pg-pager-line {
  display: flex;
  justify-content: flex-end;
  margin-left: 34px;
}
</style>
