<script setup lang="ts">
import { computed, onMounted, reactive, ref } from 'vue';
import type { Component } from 'vue';
import { ElButton, ElTag } from 'element-plus';
import { Box, DeleteFilled, Document, Menu, VideoPause, VideoPlay } from '@element-plus/icons-vue';
import { OBJECT_CONTEXT_QUERY_KEY } from '@/constants/object-context';
import { fetchGetProductOverviewSummary, fetchGetProductPage, fetchGetUserSimpleList } from '@/service/api';
import { useRouterPush } from '@/hooks/common/router';
import { getProductStatusLabel, getProductStatusTagType } from '../shared/product-master-data';
import ProductGroupedTable from './modules/product-grouped-table.vue';
import ProductOperateDialog from './modules/product-operate-dialog.vue';
import ProductSearch from './modules/product-search.vue';

defineOptions({ name: 'ProductList' });

type StatusNavTone = 'sky' | 'teal' | 'slate' | 'amber' | 'rose';

interface StatusVisualMeta {
  tone: StatusNavTone;
  icon: Component;
}

const PRODUCT_ENTRY_ROUTE_PATH = '/product/list';

function getInitSearchParams(): Api.Product.ProductSearchParams {
  return {
    pageNo: 1,
    pageSize: -1,
    keyword: '',
    directionCode: undefined,
    managerUserId: undefined,
    statusCode: undefined,
    updateTime: undefined
  };
}

function sortManagerOptions(list: Api.SystemManage.UserSimple[]) {
  return list.slice().sort((left, right) => left.nickname.localeCompare(right.nickname, 'zh-CN'));
}

/** 状态视觉资产（icon/tone）是前端本地映射；状态名直接渲染后端 statusName，不做本地名称映射 */
const STATUS_VISUALS: Record<string, StatusVisualMeta> = {
  active: { tone: 'teal', icon: VideoPlay },
  archived: { tone: 'slate', icon: Box },
  paused: { tone: 'amber', icon: VideoPause },
  abandoned: { tone: 'rose', icon: DeleteFilled }
};

/** 状态机新增状态未配置视觉资产时的默认兜底：通用图标 + 中性色 */
const DEFAULT_STATUS_VISUAL: StatusVisualMeta = { tone: 'slate', icon: Document };

const searchParams = reactive(getInitSearchParams());
/** 当前选中导航键：状态编码（状态机动态下发）或 'all'（全部视图，分页接口不传 statusCode） */
const selectedStatus = ref<string>('active');
const managerFilterOptions = ref<Api.SystemManage.UserSimple[]>([]);
const managerUserOptions = ref<Api.SystemManage.UserSimple[]>([]);
const operateVisible = ref(false);
const editingRow = ref<Api.Product.Product | null>(null);
const { routerPush } = useRouterPush();

/** 当前筛选口径下的全量产品（pageSize=-1 一次拉全），分组 / 收纳 / 假分页全在 ProductGroupedTable 内 */
const allProducts = ref<Api.Product.Product[]>([]);
const loading = ref(false);
/** 折叠全部开关（true = 全部方向折叠）；仅多方向视图有意义 */
const allCollapsed = ref(false);

/** 状态看板项（overview-summary items，状态机动态下发，已按 sort 升序） */
const statusBoardItems = ref<Api.Product.OverviewStatusItem[]>([]);
/** "全部"口径总数（后端 total，前端不自行求和） */
const statusBoardTotal = ref(0);

const managerLabelMap = computed(() => {
  return new Map(managerUserOptions.value.map(item => [String(item.id), item.nickname]));
});

/** 当前筛选口径下可见产品跨方向数：≥2 时渲染方向分层，否则单方向平铺 */
const directionCount = computed(() => new Set(allProducts.value.map(item => item.directionCode || '')).size);
const showDirectionLayer = computed(() => directionCount.value >= 2);

const statusItems = computed(() => [
  { key: 'all', label: '全部产品', count: statusBoardTotal.value, tone: 'sky' as StatusNavTone, icon: Menu },
  ...statusBoardItems.value.map(item => {
    const visual = STATUS_VISUALS[item.statusCode] ?? DEFAULT_STATUS_VISUAL;

    return {
      key: item.statusCode,
      label: item.statusName,
      count: item.count,
      tone: visual.tone,
      icon: visual.icon
    };
  })
]);

function createRequestParams(): Api.Product.ProductSearchParams {
  return {
    ...searchParams,
    pageNo: 1,
    pageSize: -1,
    keyword: searchParams.keyword?.trim() || undefined,
    statusCode: selectedStatus.value === 'all' ? undefined : selectedStatus.value
  };
}

async function loadProducts() {
  loading.value = true;

  try {
    const { error, data } = await fetchGetProductPage(createRequestParams());
    allProducts.value = !error && data ? data.list : [];
  } catch {
    allProducts.value = [];
    window.$message?.error('产品列表加载失败');
  } finally {
    loading.value = false;
  }
}

async function loadManagerOptions() {
  const { error, data: userList } = await fetchGetUserSimpleList();

  if (error || !userList) {
    managerUserOptions.value = [];
    managerFilterOptions.value = [];
    return;
  }

  const userSimpleList = sortManagerOptions(userList);
  managerUserOptions.value = userSimpleList;
  managerFilterOptions.value = userSimpleList;
}

async function loadOverviewData() {
  const { error, data: overviewSummary } = await fetchGetProductOverviewSummary();

  statusBoardItems.value = error || !overviewSummary ? [] : overviewSummary.items;
  statusBoardTotal.value = error || !overviewSummary ? 0 : overviewSummary.total;
}

async function refreshPageData() {
  await Promise.all([loadManagerOptions(), loadOverviewData(), loadProducts()]);
}

async function handleSearch() {
  await loadProducts();
}

async function handleResetSearch() {
  Object.assign(searchParams, getInitSearchParams());
  await loadProducts();
}

async function handleStatusChange(status: string) {
  selectedStatus.value = status;
  allCollapsed.value = false;
  await Promise.all([loadOverviewData(), loadProducts()]);
}

function openCreate() {
  editingRow.value = null;
  operateVisible.value = true;
}

async function enterProductContext(row: Api.Product.Product) {
  await routerPush({
    path: PRODUCT_ENTRY_ROUTE_PATH,
    query: {
      [OBJECT_CONTEXT_QUERY_KEY]: row.id
    }
  });
}

async function handleProductSubmitted(productId?: string) {
  const isEditing = Boolean(productId && editingRow.value?.id === productId);

  await refreshPageData();

  if (isEditing) {
    editingRow.value = null;
  }
}

onMounted(async () => {
  await refreshPageData();
});
</script>

<template>
  <div
    class="min-h-560px gap-16px overflow-hidden xl:grid xl:grid-cols-[396px_minmax(0,1fr)] lt-xl:flex lt-xl:flex-col lt-xl:overflow-auto"
  >
    <div class="flex-col-stretch gap-16px xl:min-h-0">
      <ElCard class="product-overview-card card-wrapper xl:flex-1">
        <div class="product-status-panel__list">
          <button
            v-for="item in statusItems"
            :key="item.key"
            type="button"
            class="product-status-item"
            :class="[`product-status-item--${item.tone}`, { 'is-active': selectedStatus === item.key }]"
            :aria-pressed="selectedStatus === item.key"
            @click="handleStatusChange(item.key)"
          >
            <div class="product-status-item__icon">
              <ElIcon>
                <component :is="item.icon" />
              </ElIcon>
            </div>
            <div class="product-status-item__main">
              <div class="product-status-item__top">
                <strong>{{ item.label }}</strong>
                <em>{{ item.count }}</em>
              </div>
            </div>
          </button>
        </div>
      </ElCard>
    </div>

    <div class="flex-col-stretch gap-16px xl:min-h-0">
      <ProductSearch
        v-model:model="searchParams"
        :manager-options="managerFilterOptions"
        @reset="handleResetSearch"
        @search="handleSearch"
      />

      <ElCard class="card-wrapper xl:flex-1-hidden" body-class="business-table-card-body">
        <template #header>
          <div class="product-card-header">
            <div class="min-w-0 flex-1">
              <div class="flex flex-wrap items-center gap-8px">
                <p class="truncate text-16px font-600">产品列表</p>
                <ElTag effect="plain" :type="getProductStatusTagType(selectedStatus)">
                  {{
                    statusItems.find(item => item.key === selectedStatus)?.label ||
                    getProductStatusLabel(selectedStatus)
                  }}
                </ElTag>
                <ElTag effect="plain">{{ allProducts.length }}</ElTag>
              </div>
            </div>
            <div class="flex flex-none items-center gap-8px">
              <ElButton
                plain
                :disabled="!showDirectionLayer || !allProducts.length"
                @click="allCollapsed = !allCollapsed"
              >
                <template #icon>
                  <icon-ic-round-unfold-more v-if="allCollapsed" class="text-icon" />
                  <icon-ic-round-unfold-less v-else class="text-icon" />
                </template>
                {{ allCollapsed ? '展开全部' : '折叠全部' }}
              </ElButton>
              <ElButton plain :loading="loading" @click="refreshPageData">
                <template #icon>
                  <icon-ic-round-refresh class="text-icon" />
                </template>
                刷新
              </ElButton>
              <ElButton plain type="primary" @click="openCreate">
                <template #icon>
                  <icon-ic-round-plus class="text-icon" />
                </template>
                新增
              </ElButton>
            </div>
          </div>
        </template>

        <div class="flex-1">
          <ProductGroupedTable
            :products="allProducts"
            :loading="loading"
            :show-direction-layer="showDirectionLayer"
            :all-collapsed="allCollapsed"
            :manager-label-map="managerLabelMap"
            @enter="enterProductContext"
          />
        </div>
      </ElCard>
    </div>

    <ProductOperateDialog
      v-model:visible="operateVisible"
      :manager-user-options="managerUserOptions"
      :row-data="editingRow"
      @submitted="handleProductSubmitted"
    />
  </div>
</template>

<style lang="scss" scoped>
.product-overview-card {
  overflow: hidden;
  border: 1px solid rgb(226 232 240 / 92%);
  background:
    radial-gradient(circle at top left, rgb(15 118 110 / 8%), transparent 36%),
    linear-gradient(180deg, rgb(255 255 255 / 99%), rgb(248 250 252 / 97%));
}

.product-status-panel__list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.product-status-item {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  padding: 14px;
  border: 1px solid rgb(226 232 240 / 90%);
  border-radius: 18px;
  background-color: rgb(255 255 255 / 86%);
  text-align: left;
  transition:
    transform 0.2s ease,
    border-color 0.2s ease,
    box-shadow 0.2s ease;
}

.product-status-item:hover {
  transform: translateY(-1px);
  border-color: rgb(148 163 184 / 60%);
}

.product-status-item.is-active {
  border-color: rgb(15 118 110 / 40%);
  box-shadow: 0 10px 24px rgb(15 118 110 / 8%);
}

.product-status-item__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 14px;
  font-size: 20px;
}

.product-status-item__main {
  min-width: 0;
  flex: 1;
}

.product-status-item__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.product-status-item__top strong {
  color: rgb(15 23 42 / 94%);
  font-size: 15px;
  font-weight: 700;
}

.product-status-item__top em {
  color: rgb(15 23 42 / 88%);
  font-size: 18px;
  font-style: normal;
  font-weight: 700;
}

.product-status-item--sky .product-status-item__icon {
  background-color: rgb(240 249 255 / 96%);
  color: rgb(2 132 199 / 96%);
}

.product-status-item--teal .product-status-item__icon {
  background-color: rgb(240 253 250 / 96%);
  color: rgb(15 118 110 / 96%);
}

.product-status-item--slate .product-status-item__icon {
  background-color: rgb(241 245 249 / 96%);
  color: rgb(51 65 85 / 92%);
}

.product-status-item--amber .product-status-item__icon {
  background-color: rgb(255 251 235 / 96%);
  color: rgb(217 119 6 / 92%);
}

.product-status-item--rose .product-status-item__icon {
  background-color: rgb(255 241 242 / 96%);
  color: rgb(225 29 72 / 92%);
}

.product-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

@media (width <= 1280px) {
  .product-card-header,
  .product-status-item__top {
    align-items: flex-start;
    flex-direction: column;
  }
}
</style>
