<script setup lang="tsx">
import { computed, onMounted, reactive, ref } from 'vue';
import { ElMessageBox } from 'element-plus';
import { FEEDBACK_STATUS_DICT_CODE, FEEDBACK_TYPE_DICT_CODE } from '@/constants/dict';
import { getFeedbackStatusTagType } from '@/constants/status-tag';
import { fetchDeleteFeedback, fetchGetFeedbackPage, fetchGetFeedbackStat } from '@/service/api';
import { useAuthStore } from '@/store/modules/auth';
import { useUIPaginatedTable } from '@/hooks/common/table';
import DictTag from '@/components/custom/dict-tag.vue';
import BusinessTableActionCell, { type BusinessTableAction } from '@/components/custom/business-table-action-cell';
import FeedbackFacet from './modules/feedback-facet.vue';
import FeedbackSearch from './modules/feedback-search.vue';
import FeedbackOperateDialog from './modules/feedback-operate-dialog.vue';
import FeedbackDetailDialog from './modules/feedback-detail-dialog.vue';
import FeedbackStatusDialog from './modules/feedback-status-dialog.vue';
import IconMdiDeleteOutline from '~icons/mdi/delete-outline';
import IconMdiEyeOutline from '~icons/mdi/eye-outline';
import IconMdiProgressCheck from '~icons/mdi/progress-check';
import IconMdiPencilOutline from '~icons/mdi/pencil-outline';

defineOptions({ name: 'Feedback' });

const authStore = useAuthStore();

// 动态路由模式下后端不返回 R_SUPER，超管按固定登录名 admin 识别（写操作放开依据）
const isSuper = computed(() => authStore.userInfo.userName === 'admin');

// 后端已移除反馈相关权限码：提交对所有登录用户开放；写操作纯前端按「归属 + 超管」控制
/** 是否本人提交 */
function isOwn(row: Api.Feedback.FeedbackItem) {
  return authStore.userInfo.userId === row.creator;
}

/** 修改状态：仅超管 */
const canUpdateStatus = computed(() => isSuper.value);

/** 删除按钮逐行显隐：自己提交的，或超管 */
function canDeleteRow(row: Api.Feedback.FeedbackItem) {
  return isOwn(row) || isSuper.value;
}

/** 编辑按钮逐行显隐：自己提交的，或超管 */
function canEditRow(row: Api.Feedback.FeedbackItem) {
  return isOwn(row) || isSuper.value;
}

function getInitSearchParams(): Api.Feedback.FeedbackSearchParams {
  return { pageNo: 1, pageSize: 20, type: undefined, status: undefined, title: undefined, creator: undefined };
}

function transformPageResult(
  response: Awaited<ReturnType<typeof fetchGetFeedbackPage>>,
  pageNo: number,
  pageSize: number
) {
  if (!response.error) {
    return { data: response.data.list, pageNum: pageNo, pageSize, total: response.data.total };
  }
  return { data: [], pageNum: pageNo, pageSize, total: 0 };
}

const searchParams = reactive(getInitSearchParams());

// 弹层 / 抽屉开关与上下文
const operateVisible = ref(false);
const operateMode = ref<'create' | 'edit'>('create');
const operateRow = ref<Api.Feedback.FeedbackItem | null>(null);
const detailVisible = ref(false);
const detailId = ref<string | null>(null);
const statusVisible = ref(false);
const statusId = ref<string | null>(null);
const statusCurrent = ref<number | null>(null);

function openCreate() {
  operateMode.value = 'create';
  operateRow.value = null;
  operateVisible.value = true;
}

function openEdit(row: Api.Feedback.FeedbackItem) {
  operateMode.value = 'edit';
  operateRow.value = row;
  operateVisible.value = true;
}

function openDetail(row: Api.Feedback.FeedbackItem) {
  detailId.value = row.id;
  detailVisible.value = true;
}

function openStatus(row: Api.Feedback.FeedbackItem) {
  statusId.value = row.id;
  statusCurrent.value = row.status;
  statusVisible.value = true;
}

const { columns, data, loading, getData, getDataByPage, mobilePagination } = useUIPaginatedTable({
  paginationProps: {
    currentPage: searchParams.pageNo,
    pageSize: searchParams.pageSize
  },
  api: () => fetchGetFeedbackPage(searchParams),
  transform: response => transformPageResult(response, searchParams.pageNo, searchParams.pageSize),
  onPaginationParamsChange: params => {
    searchParams.pageNo = params.currentPage ?? 1;
    searchParams.pageSize = params.pageSize ?? 20;
  },
  columns: () => [
    { prop: 'index', type: 'index', label: '序号', width: 64, align: 'center' },
    { prop: 'title', label: '标题', minWidth: 180, showOverflowTooltip: true },
    {
      prop: 'content',
      label: '内容',
      minWidth: 260,
      showOverflowTooltip: true,
      formatter: row => <span>{row.contentPreview}</span>
    },
    {
      prop: 'type',
      label: '分类',
      width: 110,
      align: 'center',
      formatter: row => <DictTag dictCode={FEEDBACK_TYPE_DICT_CODE} value={row.type} />
    },
    {
      prop: 'status',
      label: '状态',
      width: 110,
      align: 'center',
      formatter: row => (
        <DictTag dictCode={FEEDBACK_STATUS_DICT_CODE} value={row.status} type={getFeedbackStatusTagType(row.status)} />
      )
    },
    {
      prop: 'creatorName',
      label: '提交人',
      width: 140,
      formatter: row => <span>{row.creatorName || row.creator}</span>
    },
    { prop: 'createTime', label: '提交时间', width: 180 },
    {
      prop: 'operate',
      label: '操作',
      width: 140,
      align: 'center',
      fixed: 'right',
      formatter: row => <BusinessTableActionCell variant="icon" actions={getRowActions(row)} />
    }
  ]
});

// 左侧分面统计（全量口径，不随筛选变化；仅在进入页面与写操作后刷新）
const facetStat = ref<Api.Feedback.FeedbackStat>({ total: 0, typeCounts: {}, statusCounts: {} });
const facetLoading = ref(false);

async function loadFacet() {
  facetLoading.value = true;
  try {
    const { data: stat, error } = await fetchGetFeedbackStat();
    if (!error && stat) {
      facetStat.value = stat;
    }
  } finally {
    // 统计接口异常（含 normalize 解引用空数据抛错）也要复位，避免分面面板 v-loading 永久转圈
    facetLoading.value = false;
  }
}

async function handleDelete(row: Api.Feedback.FeedbackItem) {
  const confirmed = await ElMessageBox.confirm('确认删除该意见反馈？', '提示', { type: 'warning' })
    .then(() => true)
    .catch(() => false);
  if (!confirmed) {
    return;
  }
  const { error } = await fetchDeleteFeedback(row.id);
  if (error) {
    return;
  }
  window.$message?.success('删除成功');
  await Promise.all([getData(), loadFacet()]);
}

function getRowActions(row: Api.Feedback.FeedbackItem): BusinessTableAction[] {
  const actions: BusinessTableAction[] = [
    { key: 'detail', label: '查看详情', buttonType: 'primary', icon: IconMdiEyeOutline, onClick: () => openDetail(row) }
  ];
  if (canEditRow(row)) {
    actions.push({
      key: 'edit',
      label: '编辑',
      buttonType: 'primary',
      icon: IconMdiPencilOutline,
      onClick: () => openEdit(row)
    });
  }
  if (canUpdateStatus.value) {
    actions.push({
      key: 'status',
      label: '处理',
      buttonType: 'warning',
      icon: IconMdiProgressCheck,
      onClick: () => openStatus(row)
    });
  }
  if (canDeleteRow(row)) {
    actions.push({
      key: 'delete',
      label: '删除',
      buttonType: 'danger',
      icon: IconMdiDeleteOutline,
      onClick: () => handleDelete(row)
    });
  }
  return actions;
}

function handleSearch() {
  searchParams.pageNo = 1;
  getDataByPage(1);
}

// 搜索区「重置」清搜索区自有字段（标题、提交人）；左侧分面选中的 type/status 由分面单独控制，不在此连带清除
function resetSearchParams() {
  searchParams.title = undefined;
  searchParams.creator = undefined;
  searchParams.pageNo = 1;
  getDataByPage(1);
}

function handleSubmitted() {
  // 新增回到首页看最新；编辑只刷新当前页，避免跳页
  if (operateMode.value === 'edit') {
    getData();
  } else {
    getDataByPage(1);
  }
  loadFacet();
}

function handleStatusUpdated() {
  getData();
  loadFacet();
}

// 左侧分面点击：单选切换 toggle 由面板内部处理，这里只接收最终值并刷新列表
function handleSelectType(value?: string | number) {
  searchParams.type = value ?? undefined;
  handleSearch();
}

function handleSelectStatus(value?: string | number) {
  searchParams.status = value ?? undefined;
  handleSearch();
}

function handleSelectAll() {
  searchParams.type = undefined;
  searchParams.status = undefined;
  handleSearch();
}

onMounted(loadFacet);
</script>

<template>
  <div class="h-full flex gap-16px overflow-hidden">
    <FeedbackFacet
      class="w-200px shrink-0"
      :total="facetStat.total"
      :type-counts="facetStat.typeCounts"
      :status-counts="facetStat.statusCounts"
      :selected-type="searchParams.type"
      :selected-status="searchParams.status"
      :loading="facetLoading"
      @select-type="handleSelectType"
      @select-status="handleSelectStatus"
      @select-all="handleSelectAll"
    />

    <div class="flex-col-stretch flex-1-hidden gap-16px">
      <FeedbackSearch v-model:model="searchParams" @reset="resetSearchParams" @search="handleSearch" />

      <ElCard class="flex-1-hidden card-wrapper" body-class="business-table-card-body">
        <template #header>
          <div class="flex items-center justify-between gap-12px">
            <div class="flex items-center gap-10px">
              <p>意见反馈</p>
              <ElTag effect="plain">{{ mobilePagination.total || data.length }}</ElTag>
            </div>
            <ElButton plain type="primary" @click="openCreate">提交反馈</ElButton>
          </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" />
          </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>

    <FeedbackOperateDialog
      v-model:visible="operateVisible"
      :mode="operateMode"
      :row-data="operateRow"
      @submitted="handleSubmitted"
    />
    <FeedbackDetailDialog :id="detailId" v-model:visible="detailVisible" />
    <FeedbackStatusDialog
      :id="statusId"
      v-model:visible="statusVisible"
      :current-status="statusCurrent"
      @submitted="handleStatusUpdated"
    />
  </div>
</template>

<style scoped></style>
