<script setup lang="tsx">
import { computed, onMounted, reactive, ref } from 'vue';
import { ElButton, ElTag } from 'element-plus';
import dayjs from 'dayjs';
import { RDMS_OBJECT_DIRECTION_DICT_CODE, RDMS_PROJECT_TYPE_DICT_CODE } from '@/constants/dict';
import { OBJECT_CONTEXT_QUERY_KEY } from '@/constants/object-context';
import { fetchGetProjectOverviewSummary, fetchGetProjectPage, fetchGetUserSimpleList } from '@/service/api';
import { useDict } from '@/hooks/business/dict';
import { useRouterPush } from '@/hooks/common/router';
import { useUIPaginatedTable } from '@/hooks/common/table';
import { getProjectStatusLabel, getProjectStatusTagType } from '../shared/project-master-data';
import ProjectOperateDialog from './modules/project-operate-dialog.vue';
import ProjectOverviewCard from './modules/project-overview-card.vue';
import ProjectSearch from './modules/project-search.vue';

defineOptions({ name: 'ProjectList' });

type ProjectPageResponse = Awaited<ReturnType<typeof fetchGetProjectPage>>;

const PROJECT_ENTRY_ROUTE_PATH = '/project/list';

function getInitSearchParams(): Api.Project.ProjectSearchParams {
  return {
    pageNo: 1,
    pageSize: 10,
    keyword: '',
    directionCode: undefined,
    projectType: undefined,
    productId: undefined,
    managerUserId: undefined,
    statusCode: undefined,
    updateTime: undefined
  };
}

function transformProjectPage(response: ProjectPageResponse, pageNo: number, pageSize: number) {
  if (!response.error && response.data) {
    return {
      data: response.data.list,
      pageNum: pageNo,
      pageSize,
      total: response.data.total
    };
  }

  return {
    data: [],
    pageNum: pageNo,
    pageSize,
    total: 0
  };
}

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

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

  return dayjs(value).format('YYYY-MM-DD HH:mm:ss');
}

const searchParams = reactive(getInitSearchParams());
const selectedStatus = ref<Api.Project.ProjectStatusCode>('active');
const managerFilterOptions = ref<Api.SystemManage.UserSimple[]>([]);
const managerUserOptions = ref<Api.SystemManage.UserSimple[]>([]);
const operateVisible = ref(false);
const editingRow = ref<Api.Project.Project | null>(null);
const { routerPush } = useRouterPush();

const { getLabel: getDirectionDictLabel } = useDict(RDMS_OBJECT_DIRECTION_DICT_CODE);
const { getLabel: getProjectTypeLabel } = useDict(RDMS_PROJECT_TYPE_DICT_CODE);

const statusCounts = ref<Record<string, number>>({
  pending: 0,
  active: 0,
  paused: 0,
  completed: 0,
  cancelled: 0,
  archived: 0
});

const statusOptions = computed(() => [
  { value: 'pending', label: '待开始' },
  { value: 'active', label: '进行中' },
  { value: 'paused', label: '已暂停' },
  { value: 'completed', label: '已完成' },
  { value: 'cancelled', label: '作废项目' },
  { value: 'archived', label: '归档项目' }
]);

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

function getDirectionLabel(directionCode?: string | null) {
  return getDirectionDictLabel(directionCode, '--');
}

function getProjectTypeLabelByCode(projectType?: string | null) {
  return getProjectTypeLabel(projectType, '--');
}

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

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

function createRequestParams(): Api.Project.ProjectSearchParams {
  return {
    ...searchParams,
    keyword: searchParams.keyword?.trim() || undefined,
    statusCode: selectedStatus.value
  };
}

const { columns, columnChecks, data, loading, getDataByPage, mobilePagination } = useUIPaginatedTable<
  ProjectPageResponse,
  Api.Project.Project
>({
  paginationProps: {
    currentPage: searchParams.pageNo,
    pageSize: searchParams.pageSize
  },
  api: () => fetchGetProjectPage(createRequestParams()),
  transform: response => transformProjectPage(response, searchParams.pageNo ?? 1, searchParams.pageSize ?? 10),
  onPaginationParamsChange: params => {
    searchParams.pageNo = params.currentPage ?? 1;
    searchParams.pageSize = params.pageSize ?? 10;
  },
  columns: () => [
    { prop: 'index', type: 'index', label: '序号', width: 64 },
    {
      prop: 'projectName',
      label: '项目名称',
      minWidth: 220,
      formatter: row => (
        <ElButton link type="primary" class="project-name-link" onClick={() => enterProjectContext(row)}>
          {row.projectName}
        </ElButton>
      )
    },
    { prop: 'projectCode', label: '项目编码', minWidth: 140, showOverflowTooltip: true },
    {
      prop: 'directionCode',
      label: '项目方向',
      minWidth: 140,
      showOverflowTooltip: true,
      formatter: row => getDirectionLabel(row.directionCode)
    },
    {
      prop: 'projectType',
      label: '项目类型',
      minWidth: 140,
      showOverflowTooltip: true,
      formatter: row => getProjectTypeLabelByCode(row.projectType)
    },
    {
      prop: 'managerUserId',
      label: '项目经理',
      minWidth: 120,
      formatter: row => getManagerLabel(row.managerUserId)
    },
    {
      prop: 'progressRate',
      label: '进度',
      width: 100,
      align: 'center',
      formatter: () => '--'
    },
    {
      prop: 'statusCode',
      label: '状态',
      width: 100,
      align: 'center',
      formatter: row => (
        <ElTag type={getProjectStatusTagType(row.statusCode)}>{getProjectStatusLabel(row.statusCode)}</ElTag>
      )
    },
    {
      prop: 'updateTime',
      label: '最近更新',
      width: 170,
      align: 'center',
      formatter: row => formatDateTime(row.updateTime)
    }
  ],
  immediate: 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 fetchGetProjectOverviewSummary();

  if (error || !overviewSummary) {
    statusCounts.value = {};
    return;
  }

  statusCounts.value = overviewSummary.statusCounts || {};
}

async function reloadProjectTable(page = searchParams.pageNo ?? 1) {
  await getDataByPage(page);
}

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

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

async function handleResetSearch() {
  const pageSize = searchParams.pageSize ?? 10;

  Object.assign(searchParams, getInitSearchParams(), {
    pageSize
  });

  await reloadProjectTable(1);
}

async function handleStatusChange(status: Api.Project.ProjectStatusCode) {
  selectedStatus.value = status;
  await Promise.all([loadOverviewData(), reloadProjectTable(1)]);
}

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

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

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

  await refreshPageData(isEditing ? (searchParams.pageNo ?? 1) : 1);

  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">
      <ProjectOverviewCard
        :status-counts="statusCounts"
        :selected-status="selectedStatus"
        @status-change="handleStatusChange"
      />
    </div>

    <div class="flex-col-stretch gap-16px xl:min-h-0">
      <ProjectSearch
        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="project-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="getProjectStatusTagType(selectedStatus)">
                  {{
                    statusOptions.find(item => item.value === selectedStatus)?.label ||
                    getProjectStatusLabel(selectedStatus)
                  }}
                </ElTag>
                <ElTag effect="plain">{{ mobilePagination.total || data.length }}</ElTag>
              </div>
            </div>
            <TableHeaderOperation
              v-model:columns="columnChecks"
              :disabled-delete="true"
              :loading="loading"
              @refresh="refreshPageData"
            >
              <template #default>
                <ElButton plain type="primary" @click="openCreate">
                  <template #icon>
                    <icon-ic-round-plus class="text-icon" />
                  </template>
                  新建
                </ElButton>
              </template>
            </TableHeaderOperation>
          </div>
        </template>

        <div class="flex-1">
          <ElTable v-loading="loading" height="100%" border row-key="id" :data="data">
            <ElTableColumn v-for="col in columns" :key="String(col.prop)" v-bind="col" />

            <template #empty>
              <ElEmpty description="当前筛选条件下暂无项目" />
            </template>
          </ElTable>
        </div>
        <div class="mt-20px flex justify-end">
          <ElPagination
            v-if="mobilePagination.total"
            layout="total,prev,pager,next,sizes"
            v-bind="mobilePagination"
            @current-change="mobilePagination['current-change']"
            @size-change="mobilePagination['size-change']"
          />
        </div>
      </ElCard>
    </div>

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

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

.project-name-link {
  padding: 0;
}

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