<script setup lang="tsx">
import { computed, nextTick, reactive, ref, watch } from 'vue';
import type { TableInstance } from 'element-plus';
import { ElButton, ElTag } from 'element-plus';
import { useBoolean } from '@sa/hooks';
import { OBJECT_STATUS_MODEL_OBJECT_TYPE_DICT_CODE } from '@/constants/dict';
import {
  fetchBatchDeleteObjectStatusTransition,
  fetchDeleteObjectStatusTransition,
  fetchGetObjectStatusModelPage,
  fetchGetObjectStatusTransitionPage
} from '@/service/api';
import { useDict } from '@/hooks/business/dict';
import { useUIPaginatedTable } from '@/hooks/common/table';
import BusinessFormDialog from '@/components/custom/business-form-dialog.vue';
import BusinessTableActionCell from '@/components/custom/business-table-action-cell';
import { formatDateTime, getBooleanLabel, getBooleanTagType, getStatusLabel, getStatusTagType } from '../shared';
import StateTransitionOperateDialog from './state-transition-operate-dialog.vue';
import StateTransitionSearch from './state-transition-search.vue';

defineOptions({ name: 'StateTransitionDialog' });

interface Props {
  currentStatus?: Api.Infra.ObjectStatusModel | null;
}

const props = defineProps<Props>();

const visible = defineModel<boolean>('visible', {
  default: false
});

function getInitSearchParams(): Api.Infra.ObjectStatusTransitionSearchParams {
  return {
    pageNo: 1,
    pageSize: 10,
    objectType: props.currentStatus?.objectType,
    fromStatusCode: props.currentStatus?.statusCode,
    actionCode: undefined,
    actionName: undefined,
    toStatusCode: undefined,
    status: undefined
  };
}

function transformPageResult(
  response: Awaited<ReturnType<typeof fetchGetObjectStatusTransitionPage>>,
  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 transitionTableRef = ref<TableInstance>();
const checkedRowKeys = ref<string[]>([]);
const statusModelOptions = ref<Api.Infra.ObjectStatusModel[]>([]);
const loadingOptions = ref(false);
const { getLabel: getObjectTypeLabel } = useDict(OBJECT_STATUS_MODEL_OBJECT_TYPE_DICT_CODE);

const targetStatusOptions = computed(() =>
  statusModelOptions.value.map(item => ({
    label: `${item.statusName} (${item.statusCode})`,
    value: item.statusCode
  }))
);

const currentStatusLabel = computed(() => {
  if (!props.currentStatus) {
    return '--';
  }

  return `${props.currentStatus.statusName} (${props.currentStatus.statusCode})`;
});

const currentObjectTypeLabel = computed(() => getObjectTypeLabel(props.currentStatus?.objectType));

const { columns, columnChecks, data, loading, getData, getDataByPage, mobilePagination } = useUIPaginatedTable({
  paginationProps: {
    currentPage: searchParams.pageNo,
    pageSize: searchParams.pageSize
  },
  api: () => fetchGetObjectStatusTransitionPage(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: 'selection', type: 'selection', width: 48 },
    { prop: 'index', type: 'index', label: '序号', width: 64 },
    { prop: 'actionName', label: '动作名称', minWidth: 150, showOverflowTooltip: true },
    { prop: 'actionCode', label: '动作编码', minWidth: 150, showOverflowTooltip: true },
    {
      prop: 'toStatusCode',
      label: '目标状态',
      minWidth: 180,
      formatter: row => row.toStatusName?.trim() || row.toStatusCode
    },
    {
      prop: 'needReason',
      label: '必须填写原因',
      width: 120,
      align: 'center',
      formatter: row => <ElTag type={getBooleanTagType(row.needReason)}>{getBooleanLabel(row.needReason)}</ElTag>
    },
    {
      prop: 'status',
      label: '配置状态',
      width: 110,
      align: 'center',
      formatter: row => <ElTag type={getStatusTagType(row.status)}>{getStatusLabel(row.status)}</ElTag>
    },
    {
      prop: 'remark',
      label: '备注',
      minWidth: 180,
      showOverflowTooltip: true,
      formatter: row => row.remark || '--'
    },
    {
      prop: 'createTime',
      label: '创建时间',
      minWidth: 170,
      formatter: row => formatDateTime(row.createTime)
    },
    {
      prop: 'operate',
      label: '操作',
      width: 180,
      align: 'center',
      fixed: 'right',
      formatter: row => (
        <BusinessTableActionCell
          actions={[
            {
              key: 'edit',
              label: '编辑',
              buttonType: 'primary',
              onClick: () => openEdit(row)
            },
            {
              key: 'delete',
              label: '删除',
              buttonType: 'danger',
              onClick: () => handleDeleteAction(row)
            }
          ]}
        />
      )
    }
  ]
});

const { bool: operateVisible, setTrue: openOperateModal, setFalse: closeOperateModal } = useBoolean();
const operateType = ref<UI.TableOperateType>('add');
const editingData = ref<Api.Infra.ObjectStatusTransition | null>(null);

function openAdd() {
  operateType.value = 'add';
  editingData.value = null;
  openOperateModal();
}

function openEdit(item: Api.Infra.ObjectStatusTransition) {
  operateType.value = 'edit';
  editingData.value = item;
  openOperateModal();
}

async function handleDelete(item: Api.Infra.ObjectStatusTransition) {
  const { error } = await fetchDeleteObjectStatusTransition(item.id);

  if (error) {
    return;
  }

  window.$message?.success('删除成功');
  await reloadTable();
}

async function handleDeleteAction(row: Api.Infra.ObjectStatusTransition) {
  try {
    await window.$messageBox?.confirm('确认删除当前状态流转吗？', '警告', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    });
  } catch {
    return;
  }

  await handleDelete(row);
}

async function handleBatchDelete() {
  if (!checkedRowKeys.value.length) {
    return;
  }

  const { error } = await fetchBatchDeleteObjectStatusTransition(checkedRowKeys.value);

  if (error) {
    return;
  }

  window.$message?.success('删除成功');
  await reloadTable();
}

function handleSelectionChange(rows: Api.Infra.ObjectStatusTransition[]) {
  checkedRowKeys.value = rows.map(item => item.id);
}

async function reloadTable(page = searchParams.pageNo) {
  checkedRowKeys.value = [];
  await getDataByPage(page);
  await nextTick();
  transitionTableRef.value?.clearSelection();
}

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

function handleSearch() {
  reloadTable(1);
}

function handleSubmitted() {
  closeOperateModal();
  reloadTable();
}

async function loadStatusModelOptions() {
  if (!props.currentStatus?.objectType) {
    statusModelOptions.value = [];
    return;
  }

  loadingOptions.value = true;

  const { error, data: page } = await fetchGetObjectStatusModelPage({
    pageNo: 1,
    pageSize: 200,
    keyword: undefined,
    objectType: props.currentStatus.objectType,
    status: undefined,
    initialFlag: undefined,
    terminalFlag: undefined
  });

  loadingOptions.value = false;

  statusModelOptions.value = error ? [] : page.list;
}

async function initDialog() {
  if (!props.currentStatus) {
    return;
  }

  Object.assign(searchParams, getInitSearchParams(), {
    objectType: props.currentStatus.objectType,
    fromStatusCode: props.currentStatus.statusCode
  });

  checkedRowKeys.value = [];

  await Promise.all([loadStatusModelOptions(), reloadTable(1)]);
}

watch(
  () => [visible.value, props.currentStatus?.id] as const,
  ([opened]) => {
    if (opened) {
      initDialog();
    }
  },
  { immediate: true }
);
</script>

<template>
  <BusinessFormDialog
    v-model="visible"
    title="状态流转配置"
    width="1200px"
    :loading="loadingOptions"
    :show-footer="false"
    :scrollbar="false"
  >
    <div v-if="currentStatus" class="state-transition-dialog">
      <StateTransitionSearch
        v-model:model="searchParams"
        :target-status-options="targetStatusOptions"
        @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="min-w-0 flex flex-wrap items-center gap-8px">
              <p>状态流转列表</p>
              <ElTag type="primary" effect="light">
                {{ currentObjectTypeLabel }}
              </ElTag>
              <ElTag type="success" effect="light">
                {{ currentStatusLabel }}
              </ElTag>
              <ElTag effect="plain">{{ mobilePagination.total || data.length }}</ElTag>
            </div>
            <TableHeaderOperation
              v-model:columns="columnChecks"
              :disabled-delete="checkedRowKeys.length === 0"
              :loading="loading"
              @refresh="getData"
            >
              <template #default>
                <ElButton plain type="primary" @click="openAdd">
                  <template #icon>
                    <icon-ic-round-plus class="text-icon" />
                  </template>
                  新增
                </ElButton>
                <ElPopconfirm title="确认删除选中的状态流转吗？" @confirm="handleBatchDelete">
                  <template #reference>
                    <ElButton type="danger" plain :disabled="checkedRowKeys.length === 0">
                      <template #icon>
                        <icon-ic-round-delete class="text-icon" />
                      </template>
                      批量删除
                    </ElButton>
                  </template>
                </ElPopconfirm>
              </template>
            </TableHeaderOperation>
          </div>
        </template>

        <div class="flex-1">
          <ElTable
            ref="transitionTableRef"
            v-loading="loading"
            height="100%"
            border
            row-key="id"
            :data="data"
            @selection-change="handleSelectionChange"
          >
            <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>

    <div v-else class="h-full flex items-center justify-center">
      <ElEmpty description="请选择状态模型" />
    </div>

    <StateTransitionOperateDialog
      v-model:visible="operateVisible"
      :operate-type="operateType"
      :row-data="editingData"
      :current-status="currentStatus"
      :target-status-options="targetStatusOptions"
      append-to-body
      @submitted="handleSubmitted"
    />
  </BusinessFormDialog>
</template>

<style scoped lang="scss">
.state-transition-dialog {
  display: flex;
  min-height: 560px;
  flex-direction: column;
  gap: 16px;
}
</style>
