<script setup lang="tsx">
import { computed, reactive, ref } from 'vue';
import {
  fetchExportOperateLog,
  fetchGetOperateLog,
  fetchGetOperateLogPage,
  fetchGetUserSimpleList
} from '@/service/api';
import { useAuth } from '@/hooks/business/auth';
import { useUIPaginatedTable } from '@/hooks/common/table';
import BusinessTableActionCell, { type BusinessTableAction } from '@/components/custom/business-table-action-cell';
import LogDetailDialog from '../shared/log-detail-dialog.vue';
import { type LogDetailSection, LogPermission, downloadBlob, formatDateTime, getLogExportFileName } from '../shared';
import OperateLogSearch from './modules/search.vue';
import IconMdiEyeOutline from '~icons/mdi/eye-outline';

defineOptions({ name: 'OperateLogTab' });

type OperateLogPageResponse = Awaited<ReturnType<typeof fetchGetOperateLogPage>>;

function createSearchParams(): Api.SystemLog.Operate.SearchParams {
  return {
    pageNo: 1,
    pageSize: 10,
    userId: undefined,
    type: undefined,
    requestMethod: undefined,
    subType: undefined,
    action: undefined,
    createTime: undefined
  };
}

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

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

const { hasAuth } = useAuth();
const searchParams = reactive(createSearchParams());
const detailVisible = ref(false);
const currentRow = ref<Api.SystemLog.Operate.Log | null>(null);
const exporting = ref(false);
const userOptions = ref<Array<{ label: string; value: string }>>([]);
const canExport = computed(() => hasAuth(LogPermission.OperateExport));

const detailSections: LogDetailSection[] = [
  {
    title: '操作信息',
    fields: [
      { label: '日志编号', key: 'id' },
      { label: '操作人', key: 'userName' },
      { label: '用户编号', key: 'userId' },
      { label: '模块类型', key: 'type' },
      { label: '操作名', key: 'subType' },
      { label: '业务编号', key: 'bizId' },
      { label: '请求方式', key: 'requestMethod' },
      { label: '请求地址', key: 'requestUrl', span: 2 },
      { label: '操作时间', key: 'createTime', type: 'datetime' }
    ]
  },
  {
    title: '上下文',
    fields: [
      { label: '链路追踪编号', key: 'traceId' },
      { label: '用户IP', key: 'userIp' },
      { label: '浏览器UA', key: 'userAgent', type: 'multiline' }
    ]
  },
  {
    title: '详细内容',
    fields: [
      { label: '操作明细', key: 'action', type: 'multiline' },
      { label: '扩展字段', key: 'extra', type: 'multiline' }
    ]
  }
];

const { columns, columnChecks, data, loading, getData, getDataByPage, mobilePagination } = useUIPaginatedTable<
  OperateLogPageResponse,
  Api.SystemLog.Operate.Log
>({
  paginationProps: {
    currentPage: searchParams.pageNo,
    pageSize: searchParams.pageSize
  },
  api: () => fetchGetOperateLogPage(searchParams),
  transform: response => transformPageResult(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: 'userName', label: '操作人', minWidth: 120, showOverflowTooltip: true },
    { prop: 'type', label: '模块类型', minWidth: 140, showOverflowTooltip: true },
    { prop: 'subType', label: '操作名', minWidth: 140, showOverflowTooltip: true },
    // { prop: 'bizId', label: '业务编号', minWidth: 120, showOverflowTooltip: true },
    { prop: 'requestMethod', label: '请求方式', width: 150, align: 'center' },
    { prop: 'requestUrl', label: '请求地址', minWidth: 220, showOverflowTooltip: true },
    { prop: 'createTime', label: '操作时间', minWidth: 180, formatter: row => formatDateTime(row.createTime) },
    {
      prop: 'operate',
      label: '操作',
      width: 90,
      align: 'center',
      fixed: 'right',
      formatter: row => <BusinessTableActionCell actions={getRowActions(row)} variant="icon" />
    }
  ]
});

function getRowActions(row: Api.SystemLog.Operate.Log): BusinessTableAction[] {
  return [
    {
      key: 'view',
      label: '查看',
      buttonType: 'primary',
      icon: IconMdiEyeOutline,
      onClick: () => openDetail(row)
    }
  ];
}

function openDetail(row: Api.SystemLog.Operate.Log) {
  currentRow.value = row;
  detailVisible.value = true;
}

async function reloadTable(page = searchParams.pageNo) {
  await getDataByPage(page);
}

function resetSearchParams() {
  Object.assign(searchParams, createSearchParams());
  reloadTable(1);
}

function handleSearch() {
  reloadTable(1);
}

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

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

  userOptions.value = userList.map((item: Api.SystemManage.UserSimple) => ({
    label: item.username ? `${item.nickname}（${item.username}）` : item.nickname,
    value: item.id
  }));
}

loadUserOptions();

async function handleExport() {
  exporting.value = true;
  const { error, data: blob } = await fetchExportOperateLog(searchParams);
  exporting.value = false;

  if (error || !blob) {
    return;
  }

  downloadBlob(blob, getLogExportFileName('操作日志'));
}
</script>

<template>
  <div class="h-full min-h-0 flex-col-stretch gap-16px overflow-hidden">
    <OperateLogSearch
      v-model:model="searchParams"
      :user-options="userOptions"
      @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>
          <TableHeaderOperation
            v-model:columns="columnChecks"
            :disabled-delete="true"
            :loading="loading"
            @refresh="getData"
          >
            <template #default>
              <ElButton v-if="canExport" plain type="primary" :loading="exporting" @click="handleExport">
                <template #icon>
                  <icon-mdi-download 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" />
        </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>

    <LogDetailDialog
      v-model:visible="detailVisible"
      title="操作日志详情"
      :row-data="currentRow"
      :sections="detailSections"
      :fetch-detail="fetchGetOperateLog"
    />
  </div>
</template>
