<template>
  <div class="mes-xsl-warehouse-page">
    <div class="mes-xsl-warehouse-layout">
      <div class="mes-xsl-warehouse-sider-col">
        <aside
          :class="['mes-xsl-warehouse-sider', { 'is-collapsed': siderCollapsed, 'is-dragging': siderDragging }]"
          :style="siderAsideStyle"
        >
          <Card class="mes-xsl-warehouse-sider-card" size="small" title="仓库分类" :bordered="true">
            <template #extra>
              <a-space v-show="!siderCollapsed" size="small" class="mes-xsl-warehouse-sider-extra">
                <a-button type="link" size="small" v-auth="'xslmes:mes_xsl_warehouse_category:add'" @click="handleAddCategory">新增</a-button>
                <a-button
                  type="link"
                  size="small"
                  v-auth="'xslmes:mes_xsl_warehouse_category:edit'"
                  :disabled="!categorySelectedId"
                  @click="handleEditCategory"
                >
                  编辑
                </a-button>
                <a-button
                  type="link"
                  size="small"
                  danger
                  v-auth="'xslmes:mes_xsl_warehouse_category:delete'"
                  :disabled="!categorySelectedId"
                  @click="handleDeleteCategory"
                >
                  删除
                </a-button>
              </a-space>
            </template>
            <Spin :spinning="treeLoading">
              <BasicTree
                :treeData="categoryTreeData"
                :selectedKeys="selectedKeys"
                defaultExpandLevel="2"
                @update:selectedKeys="onTreeSelect"
              />
            </Spin>
          </Card>
        </aside>
        <!-- 分隔条：贴在侧栏右缘，三角把手 + 拖拽改宽度（与单位管理一致） -->
        <div
          class="mes-xsl-warehouse-resizer"
          :class="{ 'is-dragging': siderDragging }"
          role="separator"
          aria-orientation="vertical"
          :aria-valuenow="siderCollapsed ? 0 : siderWidth"
          :aria-valuemin="SIDER_MIN"
          :aria-valuemax="SIDER_MAX"
          tabindex="0"
          @pointerdown="onSiderResizerPointerDown"
          @keydown.left.prevent="nudgeSiderWidth(-16)"
          @keydown.right.prevent="nudgeSiderWidth(16)"
        >
          <a-tooltip :title="siderCollapsed ? '展开（可向右拖拽）' : '收起（点击）或左右拖拽调整宽度'">
            <span class="mes-xsl-warehouse-resizer-knob" aria-hidden="true">
              <span class="mes-xsl-warehouse-tri" :class="{ 'mes-xsl-warehouse-tri--collapsed': siderCollapsed }" />
            </span>
          </a-tooltip>
        </div>
      </div>
      <div class="mes-xsl-warehouse-main">
        <BasicTable @register="registerTable" :rowSelection="rowSelection">
          <template #tableTitle>
            <a-button type="primary" v-auth="'xslmes:mes_xsl_warehouse:add'" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
            <a-button type="primary" v-auth="'xslmes:mes_xsl_warehouse:exportXls'" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
            <j-upload-button type="primary" v-auth="'xslmes:mes_xsl_warehouse:importExcel'" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
            <a-dropdown v-if="selectedRowKeys.length > 0">
              <template #overlay>
                <a-menu>
                  <a-menu-item key="1" @click="batchHandleDelete">
                    <Icon icon="ant-design:delete-outlined" />
                    删除
                  </a-menu-item>
                </a-menu>
              </template>
              <a-button v-auth="'xslmes:mes_xsl_warehouse:deleteBatch'">
                批量操作
                <Icon icon="mdi:chevron-down" />
              </a-button>
            </a-dropdown>
            <super-query :config="superQueryConfig" @search="handleSuperQuery" />
          </template>
          <template #action="{ record }">
            <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
          </template>
        </BasicTable>
      </div>
    </div>
    <MesXslWarehouseModal @register="registerModal" @success="handleSuccess" />
    <MesXslWarehouseSysCategoryModal @register="registerCategoryModal" @success="onCategorySuccess" />
    <MesXslWarehouseAreaBatchAddModal @register="registerBatchAreaModal" @success="handleSuccess" />
  </div>
</template>

<script lang="ts" name="xslmes-mesXslWarehouse" setup>
  import { computed, onMounted, onUnmounted, reactive, ref } from 'vue';
  import { Card, Spin } from 'ant-design-vue';
  import { BasicTable, TableAction } from '/@/components/Table';
  import { BasicTree } from '/@/components/Tree';
  import { useModal } from '/@/components/Modal';
  import { useListPage } from '/@/hooks/system/useListPage';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { defHttp } from '/@/utils/http/axios';
  import MesXslWarehouseModal from './components/MesXslWarehouseModal.vue';
  import MesXslWarehouseSysCategoryModal from './components/MesXslWarehouseSysCategoryModal.vue';
  import MesXslWarehouseAreaBatchAddModal from './components/MesXslWarehouseAreaBatchAddModal.vue';
  import { columns, searchFormSchema, superQuerySchema, WH_CATEGORY_CUSTOMER_CODE, WH_CATEGORY_SUPPLIER_CODE } from './MesXslWarehouse.data';
  import { list, deleteOne, batchDelete, getImportUrl, getExportUrl, updateStatus } from './MesXslWarehouse.api';
  import { loadTreeData as loadCategoryTreeRoot } from '/@/views/system/category/category.api';
  import {
    fetchWarehouseCategoryRoot,
    deleteWarehouseSysCategory,
    WAREHOUSE_CATEGORY_ROOT_CODE,
  } from './MesXslWarehouseSysCategory.api';
  import Icon from '/@/components/Icon';
  import type { KeyType } from '/@/components/Tree/src/types/tree';
  import type { Recordable } from '/@/types/global';

  const { createMessage, createConfirm } = useMessage();

  const TREE_ALL = 'ALL';

  /** 侧栏宽度限制（px），与单位管理一致 */
  const SIDER_MIN = 200;
  const SIDER_MAX = 560;
  const SIDER_DEFAULT = 260;
  const SIDER_DRAG_THRESHOLD = 5;
  const SIDER_EXPAND_DRAG = 12;

  const siderCollapsed = ref(false);
  const siderWidth = ref(SIDER_DEFAULT);
  const siderDragging = ref(false);
  const treeLoading = ref(false);

  const siderAsideStyle = computed(() => ({
    width: siderCollapsed.value ? '0px' : `${siderWidth.value}px`,
  }));

  let siderDragStartX = 0;
  let siderDragStartW = 0;
  let siderDragMaxDelta = 0;
  let siderDragCollapsedStart = false;
  let siderDragPointerId: number | null = null;
  let siderDragEl: HTMLElement | null = null;

  function toggleSider() {
    siderCollapsed.value = !siderCollapsed.value;
  }

  function clampSiderW(w: number) {
    return Math.min(SIDER_MAX, Math.max(SIDER_MIN, w));
  }

  function nudgeSiderWidth(delta: number) {
    if (siderCollapsed.value) {
      if (delta > 0) {
        siderCollapsed.value = false;
      } else {
        return;
      }
    }
    siderWidth.value = clampSiderW(siderWidth.value + delta);
  }

  function onSiderResizerPointerMove(e: PointerEvent) {
    if (siderDragPointerId == null || e.pointerId !== siderDragPointerId) return;
    const dx = e.clientX - siderDragStartX;
    siderDragMaxDelta = Math.max(siderDragMaxDelta, Math.abs(dx));

    if (siderDragCollapsedStart) {
      if (dx >= SIDER_EXPAND_DRAG) {
        siderCollapsed.value = false;
        siderWidth.value = clampSiderW(dx);
        siderDragStartX = e.clientX;
        siderDragStartW = siderWidth.value;
        siderDragCollapsedStart = false;
      }
    } else {
      siderWidth.value = clampSiderW(siderDragStartW + dx);
    }
  }

  function endSiderDrag(e: PointerEvent) {
    if (siderDragPointerId == null || e.pointerId !== siderDragPointerId) return;
    if (siderDragEl) {
      try {
        siderDragEl.releasePointerCapture(siderDragPointerId);
      } catch {
        /* ignore */
      }
    }
    document.removeEventListener('pointermove', onSiderResizerPointerMove);
    document.removeEventListener('pointerup', endSiderDrag);
    document.removeEventListener('pointercancel', endSiderDrag);
    document.body.style.cursor = '';
    document.body.style.userSelect = '';
    siderDragging.value = false;
    siderDragPointerId = null;
    siderDragEl = null;

    if (siderDragMaxDelta < SIDER_DRAG_THRESHOLD) {
      toggleSider();
    }
  }

  function onSiderResizerPointerDown(e: PointerEvent) {
    if (e.button !== 0) return;
    e.preventDefault();
    siderDragEl = e.currentTarget as HTMLElement;
    siderDragPointerId = e.pointerId;
    siderDragStartX = e.clientX;
    siderDragStartW = siderCollapsed.value ? 0 : siderWidth.value;
    siderDragMaxDelta = 0;
    siderDragCollapsedStart = siderCollapsed.value;
    siderDragging.value = true;
    document.body.style.cursor = 'col-resize';
    document.body.style.userSelect = 'none';
    try {
      siderDragEl.setPointerCapture(e.pointerId);
    } catch {
      /* ignore */
    }
    document.addEventListener('pointermove', onSiderResizerPointerMove);
    document.addEventListener('pointerup', endSiderDrag);
    document.addEventListener('pointercancel', endSiderDrag);
  }

  onUnmounted(() => {
    document.removeEventListener('pointermove', onSiderResizerPointerMove);
    document.removeEventListener('pointerup', endSiderDrag);
    document.removeEventListener('pointercancel', endSiderDrag);
    document.body.style.cursor = '';
    document.body.style.userSelect = '';
  });

  /** 分类字典异步树根（pcode=XSLMES_WH 下的子树：一楼库、二楼仓库…） */
  const rawWarehouseCategoryTree = ref<Recordable[]>([]);
  /** 根节点 id（编码 XSLMES_WH），新增「顶级子节点」时用 */
  const warehouseCategoryRootId = ref('');

  const queryParam = reactive<any>({});
  const selectedKeys = ref<KeyType[]>([TREE_ALL]);

  const categorySelectedId = computed(() => {
    const k = selectedKeys.value[0];
    if (!k || k === TREE_ALL) return '';
    return String(k);
  });

  function mapCategoryTreeNodes(nodes: Recordable[]): Recordable[] {
    return (nodes || []).map((n) => ({
      key: n.key,
      title: n.title,
      children: n.children?.length ? mapCategoryTreeNodes(n.children as Recordable[]) : undefined,
    }));
  }

  const categoryTreeData = computed(() => [
    {
      key: TREE_ALL,
      title: '全部分类',
      children: mapCategoryTreeNodes(rawWarehouseCategoryTree.value || []),
    },
  ]);

  function collectLeafKeysUnder(node: Recordable): string[] {
    const children = node.children as Recordable[] | undefined;
    if (!children?.length) {
      return [String(node.key)];
    }
    return children.flatMap((ch) => collectLeafKeysUnder(ch));
  }

  function findNodeByKey(nodes: Recordable[], key: string): Recordable | null {
    for (const n of nodes) {
      if (String(n.key) === key) {
        return n;
      }
      const nested = n.children as Recordable[] | undefined;
      if (nested?.length) {
        const found = findNodeByKey(nested, key);
        if (found) {
          return found;
        }
      }
    }
    return null;
  }

  async function loadCategoryTree() {
    treeLoading.value = true;
    try {
      const root = await fetchWarehouseCategoryRoot();
      warehouseCategoryRootId.value = root?.id != null ? String(root.id) : '';
      const res = await loadCategoryTreeRoot({ async: false, pcode: 'XSLMES_WH' });
      rawWarehouseCategoryTree.value = Array.isArray(res) ? res : [];
      if (!warehouseCategoryRootId.value || !rawWarehouseCategoryTree.value.length) {
        createMessage.warning('未加载到仓库分类树，请确认已执行库脚本并已在「分类字典」中维护根节点 XSLMES_WH。');
      }
    } catch {
      warehouseCategoryRootId.value = '';
      rawWarehouseCategoryTree.value = [];
      createMessage.warning('加载分类字典失败，请检查分类根编码 XSLMES_WH 是否存在。');
    } finally {
      treeLoading.value = false;
    }
  }

  const [registerModal, { openModal }] = useModal();
  const [registerCategoryModal, { openModal: openCategoryModal }] = useModal();
  const [registerBatchAreaModal, { openModal: openBatchAreaModal }] = useModal();

  function handleAddCategory() {
    const rootId = warehouseCategoryRootId.value;
    if (!rootId) {
      createMessage.warning('未找到仓库分类根节点，请确认分类字典中存在编码「XSLMES_WH」');
      return;
    }
    const sel = categorySelectedId.value;
    const parentId = sel || rootId;
    openCategoryModal(true, { isUpdate: false, parentId });
  }

  function handleEditCategory() {
    const id = categorySelectedId.value;
    if (!id) {
      createMessage.warning('请先选择左侧分类');
      return;
    }
    openCategoryModal(true, { isUpdate: true, record: { id } });
  }

  async function handleDeleteCategory() {
    const id = categorySelectedId.value;
    if (!id) {
      createMessage.warning('请先选择要删除的分类');
      return;
    }
    if (id === warehouseCategoryRootId.value) {
      createMessage.warning('根分类不可删除');
      return;
    }
    let code = '';
    try {
      const cat = await defHttp.get<Recordable>({ url: '/sys/category/queryById', params: { id } });
      code = cat?.code != null ? String(cat.code) : '';
    } catch {
      createMessage.error('无法读取分类信息');
      return;
    }
    if (code === WAREHOUSE_CATEGORY_ROOT_CODE) {
      createMessage.warning('根分类不可删除');
      return;
    }
    if (code === WH_CATEGORY_CUSTOMER_CODE || code === WH_CATEGORY_SUPPLIER_CODE) {
      createMessage.warning('「客户库」「供应商库」为业务保留分类，不建议删除');
      return;
    }
    createConfirm({
      iconType: 'warning',
      title: '确认删除',
      content: '将删除该节点及其下级分类；已选用这些分类的仓库数据不会自动变更，请确认无业务影响。',
      onOk: async () => {
        await deleteWarehouseSysCategory(id);
        await loadCategoryTree();
        selectedKeys.value = [TREE_ALL];
        delete queryParam.warehouseCategory;
        delete queryParam.warehouseCategory_MultiString;
        reload();
      },
    });
  }

  function onCategorySuccess() {
    loadCategoryTree();
    reload();
  }

  const { tableContext, onExportXls, onImportXls } = useListPage({
    tableProps: {
      title: '仓库管理',
      api: list,
      columns,
      canResize: true,
      formConfig: {
        schemas: searchFormSchema,
        autoSubmitOnEnter: true,
        showAdvancedButton: true,
      },
      actionColumn: {
        width: 300,
        fixed: 'right',
      },
      beforeFetch: (params) => Object.assign(params, queryParam),
    },
    exportConfig: {
      name: '仓库管理',
      url: getExportUrl,
      params: queryParam,
    },
    importConfig: {
      url: getImportUrl,
      success: handleSuccess,
    },
  });

  const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
  const superQueryConfig = reactive(superQuerySchema);

  onMounted(async () => {
    await loadCategoryTree();
    reload();
  });

  function onTreeSelect(keys: KeyType[]) {
    selectedKeys.value = keys;
    const k = keys[0];
    delete queryParam.warehouseCategory;
    delete queryParam.warehouseCategory_MultiString;
    if (!k || k === TREE_ALL) {
      reload();
      return;
    }
    const node = findNodeByKey(rawWarehouseCategoryTree.value, String(k));
    if (!node) {
      reload();
      return;
    }
    const leafKeys = collectLeafKeysUnder(node);
    if (leafKeys.length === 1) {
      queryParam.warehouseCategory = leafKeys[0];
    } else if (leafKeys.length > 1) {
      queryParam.warehouseCategory_MultiString = leafKeys.join(',');
    }
    reload();
  }

  function handleSuperQuery(params) {
    Object.keys(params).forEach((k) => {
      queryParam[k] = params[k];
    });
    reload();
  }

  function handleAdd() {
    openModal(true, { isUpdate: false, showFooter: true, record: {} });
  }

  function handleEdit(record: Recordable) {
    openModal(true, { record, isUpdate: true, showFooter: true });
  }

  function handleDetail(record: Recordable) {
    openModal(true, { record, isUpdate: true, showFooter: false });
  }

  async function handleDelete(record) {
    await deleteOne({ id: record.id }, handleSuccess);
  }

  function isRecordEnabled(record: Recordable) {
    return record.status === '0' || record.status === 0;
  }

  async function handleToggleStatus(record: Recordable, status: string) {
    await updateStatus({ id: record.id, status }, handleSuccess);
  }

  async function batchHandleDelete() {
    await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
  }

  function handleSuccess() {
    selectedRowKeys.value = [];
    reload();
  }

  function getTableAction(record) {
    const enabled = isRecordEnabled(record);
    return [
      {
        label: '编辑',
        onClick: handleEdit.bind(null, record),
        auth: 'xslmes:mes_xsl_warehouse:edit',
      },
      {
        label: '启用',
        ifShow: !enabled,
        onClick: handleToggleStatus.bind(null, record, '0'),
        auth: 'xslmes:mes_xsl_warehouse:updateStatus',
      },
      {
        label: '停用',
        ifShow: enabled,
        onClick: handleToggleStatus.bind(null, record, '1'),
        auth: 'xslmes:mes_xsl_warehouse:updateStatus',
      },
      {
        label: '删除',
        popConfirm: {
          title: '是否确认删除',
          confirm: handleDelete.bind(null, record),
        },
        auth: 'xslmes:mes_xsl_warehouse:delete',
      },
    ];
  }

  function handleBatchAddArea(record: Recordable) {
    openBatchAreaModal(true, { record });
  }

  function getDropDownAction(record) {
    return [
      { label: '详情', onClick: handleDetail.bind(null, record) },
      { label: '批量添加库区', onClick: handleBatchAddArea.bind(null, record) },
    ];
  }
</script>

<style lang="less" scoped>
  .mes-xsl-warehouse-page {
    display: flex;
    flex-direction: column;
    min-height: calc(100vh - 160px);

    :deep(.ant-picker-range) {
      width: 100%;
    }
  }

  .mes-xsl-warehouse-layout {
    display: flex;
    flex: 1;
    align-items: stretch;
    gap: 0;
    min-height: 0;
  }

  .mes-xsl-warehouse-sider-col {
    display: flex;
    flex-direction: row;
    align-items: stretch;
    flex: 0 0 auto;
    min-height: 0;
  }

  .mes-xsl-warehouse-sider {
    flex: 0 0 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
    transition: width 0.2s ease;

    .mes-xsl-warehouse-sider-extra {
      display: flex;
      align-items: center;
      flex-wrap: wrap;
      justify-content: flex-end;
      gap: 0;
      max-width: 200px;
    }

    &.is-dragging {
      transition: none;
    }

    &.is-collapsed {
      pointer-events: none;
    }
  }

  .mes-xsl-warehouse-sider-card {
    height: 100%;
    display: flex;
    flex-direction: column;
    min-height: 0;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);

    :deep(.ant-card-head) {
      min-height: 40px;
      padding: 0 12px;
    }

    :deep(.ant-card-body) {
      flex: 1;
      overflow: auto;
      min-height: 0;
      padding: 8px 12px;
    }
  }

  .mes-xsl-warehouse-resizer {
    flex: 0 0 8px;
    width: 8px;
    position: relative;
    z-index: 2;
    cursor: col-resize;
    touch-action: none;
    user-select: none;
    background: #fafafa;
    margin-right: 2px;

    &:hover,
    &:focus-visible {
      background: #f0f0f0;
    }

    &.is-dragging {
      background: #e6f4ff;
    }
  }

  .mes-xsl-warehouse-resizer-knob {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 10px;
    height: 44px;
    pointer-events: none;
    background: #fff;
    border: 1px solid #e8e8e8;
    border-radius: 2px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
  }

  .mes-xsl-warehouse-tri {
    display: block;
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 5px 6px 5px 0;
    border-color: transparent #595959 transparent transparent;
    margin-left: -1px;
  }

  .mes-xsl-warehouse-tri--collapsed {
    border-width: 5px 0 5px 6px;
    border-color: transparent transparent transparent #595959;
    margin-left: 0;
    margin-right: -1px;
  }

  .mes-xsl-warehouse-main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    min-height: 0;
  }
</style>
