<script setup lang="ts">
import { computed, onMounted, reactive, ref } from 'vue';
import { ElButton } from 'element-plus';
import { OBJECT_CONTEXT_QUERY_KEY } from '@/constants/object-context';
import {
  fetchGetProductPage,
  fetchGetProjectGroupPage,
  fetchGetProjectOverviewSummary,
  fetchGetProjectPage,
  fetchGetUserSimpleList
} from '@/service/api';
import { useRouterPush } from '@/hooks/common/router';
import ProjectGroupedTable from './modules/project-grouped-table.vue';
import ProjectOperateDialog from './modules/project-operate-dialog.vue';
import ProjectSearch from './modules/project-search.vue';
import ProjectStatusRail, { type ProjectListNavKey } from './modules/project-status-rail.vue';

defineOptions({ name: 'ProjectList' });

const PROJECT_ENTRY_ROUTE_PATH = '/project/list';
/** 组内默认直出条数（设计决策 N=5，超出收纳为"还有 X 个"；与后端 group-page topN 对齐） */
const GROUP_TOP_N = 5;
/** 每页产品组数（设计决策 M=10，按产品分页） */
const GROUP_PAGE_SIZE = 10;
/** 展开剩余单次拉取上限（内网单产品项目量级内安全） */
const GROUP_REMAINING_PAGE_SIZE = 200;

function getInitSearchParams(): Api.Project.ProjectGroupSearchParams {
  return {
    pageNo: 1,
    pageSize: GROUP_PAGE_SIZE,
    keyword: '',
    productId: undefined,
    projectType: undefined,
    statusCode: undefined,
    orphanOnly: undefined
  };
}

function createEmptyGroupPage(): Api.Project.ProjectGroupPageResult {
  return { total: 0, projectTotal: 0, directionCount: 0, orphanTotal: 0, list: [] };
}

const searchParams = reactive(getInitSearchParams());
const navKey = ref<ProjectListNavKey>('active');
const groupPage = ref<Api.Project.ProjectGroupPageResult>(createEmptyGroupPage());
const loading = ref(false);
const allCollapsed = ref(false);
/** 状态看板项（overview-summary items，状态机动态下发），左栏与"全部"口径派生均以此为源 */
const statusBoardItems = ref<Api.Project.OverviewStatusItem[]>([]);
/** "全部"口径总数（后端 total，前端不自行求和） */
const statusBoardTotal = ref(0);
/** 游离项目数：取 overview-summary 的 orphanCount（全口径常驻），左栏游离入口据此显隐 */
const orphanCount = ref(0);
const managerUserOptions = ref<Api.SystemManage.UserSimple[]>([]);
const productOptions = ref<Array<{ id: string; name: string }>>([]);
const operateVisible = ref(false);
const presetProduct = ref<{ id: string; name: string } | null>(null);
const { routerPush } = useRouterPush();

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

const showDirectionLayer = computed(() => groupPage.value.directionCount >= 2);

/** "全部"视图状态编码：由状态看板项按 includeInAll 派生（当前口径无排除项），用于展开剩余时 statusCodes 多值过滤 */
const allViewStatusCodes = computed(() =>
  statusBoardItems.value.filter(item => item.includeInAll).map(item => item.statusCode)
);

const headerMeta = computed(() => {
  const parts: string[] = [];

  if (showDirectionLayer.value) {
    parts.push(`跨 ${groupPage.value.directionCount} 个方向`);
  }

  parts.push(`${groupPage.value.total} 个分组`);
  parts.push(`${groupPage.value.projectTotal} 个项目`);

  return parts.join(' · ');
});

function createRequestParams(): Api.Project.ProjectGroupSearchParams {
  const isStatusNav = navKey.value !== 'all' && navKey.value !== 'orphan';

  return {
    ...searchParams,
    keyword: searchParams.keyword?.trim() || undefined,
    topN: GROUP_TOP_N,
    statusCode: isStatusNav ? navKey.value : undefined,
    orphanOnly: navKey.value === 'orphan' ? true : undefined
  };
}

async function loadGroupPage(page = searchParams.pageNo ?? 1) {
  searchParams.pageNo = page;
  loading.value = true;

  const { error, data } = await fetchGetProjectGroupPage(createRequestParams());

  loading.value = false;
  groupPage.value = !error && data ? data : createEmptyGroupPage();
}

/**
 * 展开某组剩余项目：后端 group-page 每组仅返前 topN 条，剩余按当前视图状态口径 +
 * 产品/游离维度走 page 接口拉该组全量，回灌给分组表格组件（注入到其 fetchMore）。
 */
async function loadGroupRemaining(group: Api.Project.ProjectGroup): Promise<Api.Project.Project[]> {
  const isStatusNav = navKey.value !== 'all' && navKey.value !== 'orphan';

  const { error, data } = await fetchGetProjectPage({
    pageNo: 1,
    pageSize: GROUP_REMAINING_PAGE_SIZE,
    keyword: searchParams.keyword?.trim() || undefined,
    projectType: searchParams.projectType || undefined,
    productId: group.orphan ? undefined : (group.productId ?? undefined),
    orphanOnly: group.orphan ? true : undefined,
    statusCode: isStatusNav ? navKey.value : undefined,
    statusCodes: isStatusNav ? undefined : allViewStatusCodes.value
  });

  if (error || !data) {
    throw new Error('加载该组剩余项目失败');
  }

  return data.list;
}

async function loadOverviewData() {
  const { error, data } = await fetchGetProjectOverviewSummary();

  statusBoardItems.value = error || !data ? [] : data.items;
  statusBoardTotal.value = error || !data ? 0 : data.total;
  orphanCount.value = error || !data ? 0 : (data.orphanCount ?? 0);
}

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

  managerUserOptions.value =
    error || !data ? [] : data.slice().sort((left, right) => left.nickname.localeCompare(right.nickname, 'zh-CN'));
}

async function loadProductOptions() {
  const { error, data } = await fetchGetProductPage({ pageNo: 1, pageSize: 200 });

  productOptions.value =
    error || !data
      ? []
      : data.list.map(item => ({
          id: item.id,
          name: item.name || item.code || item.id
        }));
}

async function refreshPageData(page = searchParams.pageNo ?? 1) {
  await Promise.all([loadManagerOptions(), loadProductOptions(), loadOverviewData(), loadGroupPage(page)]);
}

async function handleSearch() {
  await loadGroupPage(1);
}

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

async function handleNavChange(key: ProjectListNavKey) {
  navKey.value = key;
  allCollapsed.value = false;
  await Promise.all([loadOverviewData(), loadGroupPage(1)]);
}

function openCreate(group?: Api.Project.ProjectGroup) {
  presetProduct.value = group?.productId ? { id: group.productId, name: group.productName } : null;
  operateVisible.value = true;
}

async function enterProjectContext(project: Api.Project.Project) {
  await routerPush({
    path: PROJECT_ENTRY_ROUTE_PATH,
    query: {
      [OBJECT_CONTEXT_QUERY_KEY]: project.id
    }
  });
}

async function handleProjectSubmitted() {
  await Promise.all([loadOverviewData(), loadGroupPage(searchParams.pageNo ?? 1)]);
}

onMounted(async () => {
  await refreshPageData(1);
});
</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 xl:overflow-auto">
      <ProjectStatusRail
        class="xl:flex-1"
        :items="statusBoardItems"
        :total="statusBoardTotal"
        :orphan-count="orphanCount"
        :selected="navKey"
        @change="handleNavChange"
      />
    </div>

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

      <ElCard class="card-wrapper xl:flex-1-hidden" body-class="business-table-card-body">
        <template #header>
          <div class="project-card-header">
            <div class="min-w-0 flex flex-wrap items-center gap-8px">
              <p class="truncate text-16px font-600">项目列表</p>
              <span class="project-card-header__meta">{{ headerMeta }}</span>
            </div>
            <div class="flex flex-none items-center gap-8px">
              <ElButton plain :disabled="!groupPage.list.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 type="primary" @click="openCreate()">
                <template #icon>
                  <icon-ic-round-plus class="text-icon" />
                </template>
                新增项目
              </ElButton>
            </div>
          </div>
        </template>

        <div class="flex-1">
          <ProjectGroupedTable
            :groups="groupPage.list"
            :loading="loading"
            :all-view="navKey === 'all'"
            :show-direction-layer="showDirectionLayer"
            :top-n="GROUP_TOP_N"
            :all-collapsed="allCollapsed"
            :manager-label-map="managerLabelMap"
            :fetch-more="loadGroupRemaining"
            @enter="enterProjectContext"
            @create="openCreate"
          />
        </div>
        <div class="mt-20px flex justify-end">
          <ElPagination
            v-if="groupPage.total > GROUP_PAGE_SIZE"
            layout="total,prev,pager,next"
            :total="groupPage.total"
            :page-size="GROUP_PAGE_SIZE"
            :current-page="searchParams.pageNo ?? 1"
            @current-change="loadGroupPage"
          />
        </div>
      </ElCard>
    </div>

    <ProjectOperateDialog
      v-model:visible="operateVisible"
      :manager-user-options="managerUserOptions"
      :preset-product="presetProduct"
      @submitted="handleProjectSubmitted"
    />
  </div>
</template>

<style lang="scss" scoped>
.project-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.project-card-header__meta {
  color: var(--el-text-color-secondary);
  font-size: 13px;
}

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