<template>
  <BasicModal
    v-bind="$attrs"
    title="选择密炼物料"
    :width="1180"
    :getContainer="getModalContainer"
    @register="registerModal"
    @ok="handleOk"
  >
    <div class="mixing-material-picker">
      <div class="mixing-material-picker-toolbar">
        <a-input
          v-model:value="keyword"
          allow-clear
          placeholder="关键字（物料编码/名称/描述）"
          style="width: 280px"
          @pressEnter="reloadTable"
        />
        <a-button type="primary" @click="reloadTable">搜索</a-button>
        <MesXslMixingMaterialCategorySetting
          v-model:hiddenCategoryIds="hiddenCategoryIds"
          :categories="allMinorCategories"
          :loading="treeLoading"
          @change="handleCategoryVisibilityChange"
        />
      </div>
      <div class="mixing-material-picker-body">
        <aside class="mixing-material-picker-sider">
          <div class="mixing-material-picker-sider-title">物料小类</div>
          <Spin :spinning="treeLoading">
            <BasicTree
              :treeData="visibleCategoryTree"
              :selectedKeys="selectedCategoryKeys"
              :expandedKeys="expandedCategoryKeys"
              defaultExpandLevel="2"
              @update:selectedKeys="onCategorySelect"
              @update:expandedKeys="onExpandedKeysChange"
            />
          </Spin>
        </aside>
        <div class="mixing-material-picker-main">
          <BasicTable @register="registerTable">
            <template #bodyCell="{ column, record }">
              <template v-if="column.dataIndex === 'pickerWeighMode'">
                <div class="mixing-material-picker-weigh-mode" @click.stop>
                  <JDictSelectTag
                    :value="getPickerWeighMode(record.id)"
                    :dictCode="MIXING_MATERIAL_PICKER_WEIGH_MODE_DICT"
                    :getPopupContainer="getSelectPopupContainer"
                    :showChooseOption="false"
                    placeholder="请选择"
                    popupClassName="mixing-material-picker-weigh-mode-dropdown"
                    style="width: 100%"
                    @change="(val) => setPickerWeighMode(record.id, val)"
                  />
                </div>
              </template>
            </template>
          </BasicTable>
        </div>
      </div>
    </div>
  </BasicModal>
</template>

<script lang="ts" setup>
  import { computed, onMounted, ref, watch } from 'vue';
  import { Spin } from 'ant-design-vue';
  import { BasicModal, useModalInner } from '/@/components/Modal';
  import { BasicTable, useTable } from '/@/components/Table';
  import { BasicTree } from '/@/components/Tree';
  import { defHttp } from '/@/utils/http/axios';
  import { loadMesMaterialCategoryTreeData } from '/@/views/system/category/category.constants';
  import { list as mixerList, queryById as queryMixerById } from '/@/views/mes/material/MesMixerMaterial.api';
  import { useMessage } from '/@/hooks/web/useMessage';
  import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
  import MesXslMixingMaterialCategorySetting from './MesXslMixingMaterialCategorySetting.vue';
  import {
    applyMixingMaterialFromSelection,
    loadMixingMaterialPickerHiddenCategoryIds,
    MIXING_MATERIAL_PICKER_WEIGH_MODE_DICT,
    mixingMaterialPickerTableColumns,
    resolveMixingMaterialKindForPicker,
    sanitizeMixingMaterialPickerHiddenCategoryIds,
    saveMixingMaterialPickerHiddenCategoryIds,
    type MixingMaterialPickerCategoryItem,
  } from '../MesXslMixingSpec.data';
  import type { KeyType } from '/@/components/Tree/src/types/tree';

  const TREE_ALL = 'ALL';
  const emit = defineEmits(['register', 'select']);
  const { createMessage } = useMessage();

  const keyword = ref('');
  const treeLoading = ref(false);
  const rawCategoryTree = ref<Recordable[]>([]);
  const allMajorCategories = ref<Array<{ id: string; name: string; minors: MixingMaterialPickerCategoryItem[] }>>([]);
  const allMinorCategories = ref<MixingMaterialPickerCategoryItem[]>([]);
  const hiddenCategoryIds = ref<string[]>(loadMixingMaterialPickerHiddenCategoryIds());
  const selectedCategoryKeys = ref<KeyType[]>([TREE_ALL]);
  const expandedCategoryKeys = ref<KeyType[]>([TREE_ALL]);
  const selectedRow = ref<Recordable | null>(null);
  const categoryRubberMap = ref<Record<string, boolean>>({});
  const pickerWeighModeMap = ref<Record<string, string>>({});

  const hiddenCategoryIdSet = computed(() => new Set(hiddenCategoryIds.value.map(String)));

  function getModalContainer() {
    return document.body;
  }

  function getSelectPopupContainer() {
    return document.body;
  }

  function filterHiddenCategoryTree(nodes: Recordable[], hidden: Set<string>): Recordable[] {
    return (nodes || [])
      .map((major) => {
        const children = (major.children || [])
          .filter((minor) => !hidden.has(String(minor.key)))
          .map((minor) => ({
            key: minor.key,
            title: minor.title,
          }));
        if (!children.length) {
          return null;
        }
        return {
          key: major.key,
          title: major.title,
          children,
        };
      })
      .filter(Boolean) as Recordable[];
  }

  const visibleCategoryTree = computed(() => [
    {
      key: TREE_ALL,
      title: '全部小类',
      children: filterHiddenCategoryTree(rawCategoryTree.value, hiddenCategoryIdSet.value),
    },
  ]);

  function syncExpandedCategoryKeys() {
    const keys: KeyType[] = [TREE_ALL];
    for (const major of visibleCategoryTree.value[0]?.children || []) {
      keys.push(major.key);
    }
    expandedCategoryKeys.value = keys;
  }

  watch(
    visibleCategoryTree,
    () => {
      syncExpandedCategoryKeys();
    },
    { deep: true },
  );

  const selectedCategoryFilter = computed(() => {
    const key = selectedCategoryKeys.value[0];
    if (!key || key === TREE_ALL) {
      return {};
    }
    const keyStr = String(key);
    const major = allMajorCategories.value.find((item) => item.id === keyStr);
    if (major) {
      return { majorCategoryId: major.id };
    }
    return { minorCategoryId: keyStr };
  });

  const [registerTable, { reload, getSelectRowKeys, getSelectRows, clearSelectedRowKeys }] = useTable({
    api: mixerList,
    columns: mixingMaterialPickerTableColumns,
    rowKey: 'id',
    useSearchForm: false,
    pagination: { pageSize: 10 },
    canResize: false,
    showIndexColumn: true,
    immediate: true,
    beforeFetch: (params) => {
      const next = { ...params, ...selectedCategoryFilter.value };
      const kw = keyword.value?.trim();
      if (kw) {
        next.materialName = `*${kw}*`;
      }
      return next;
    },
    rowSelection: {
      type: 'radio',
      columnWidth: 48,
      onChange: (_keys, rows) => {
        selectedRow.value = rows?.[0] ?? null;
      },
    },
    clickToRowSelect: true,
  });

  //update-begin---author:cursor ---date:20260525  for：【XSLMES-20260525-A50】选料弹窗打开时初始化（对齐其他SelectModal）-----------
  const [registerModal, { setModalProps, closeModal }] = useModalInner(async () => {
    await initPickerModal();
  });

  async function initPickerModal() {
    selectedRow.value = null;
    keyword.value = '';
    pickerWeighModeMap.value = {};
    clearSelectedRowKeys?.();
    hiddenCategoryIds.value = loadMixingMaterialPickerHiddenCategoryIds();
    selectedCategoryKeys.value = [TREE_ALL];
    setModalProps({ confirmLoading: false });
    await loadMaterialCategoryTree();
    reloadTable();
  }

  onMounted(() => {
    loadMaterialCategoryTree();
  });
  //update-end---author:cursor ---date:20260525  for：【XSLMES-20260525-A50】选料弹窗打开时初始化（对齐其他SelectModal）-----------

  async function loadMaterialCategoryTree() {
    treeLoading.value = true;
    try {
      const { majors, minors, treeNodes } = await loadMesMaterialCategoryTreeData();
      rawCategoryTree.value = treeNodes;
      allMajorCategories.value = majors;
      allMinorCategories.value = minors;

      const sanitizedHidden = sanitizeMixingMaterialPickerHiddenCategoryIds(
        minors.map((item) => item.id),
        hiddenCategoryIds.value,
      );
      if (sanitizedHidden.length !== hiddenCategoryIds.value.length) {
        hiddenCategoryIds.value = sanitizedHidden;
        saveMixingMaterialPickerHiddenCategoryIds(sanitizedHidden);
      }

      categoryRubberMap.value = {};
      syncExpandedCategoryKeys();

      if (!minors.length) {
        createMessage.warning('未加载到物料小类，请确认分类字典根编码 XSLMES_MATERIAL 及其下级分类已配置。');
      }
    } catch {
      rawCategoryTree.value = [];
      allMajorCategories.value = [];
      allMinorCategories.value = [];
      createMessage.warning('加载物料分类树失败，请检查分类根编码 XSLMES_MATERIAL 是否存在。');
    } finally {
      treeLoading.value = false;
    }
  }

  function reloadTable() {
    reload();
  }

  function getPickerWeighMode(materialId?: string) {
    if (!materialId) {
      return undefined;
    }
    return pickerWeighModeMap.value[String(materialId)];
  }

  function setPickerWeighMode(materialId: string | undefined, value?: string) {
    if (!materialId) {
      return;
    }
    const key = String(materialId);
    const next = { ...pickerWeighModeMap.value };
    if (value == null || value === '') {
      delete next[key];
    } else {
      next[key] = String(value);
    }
    pickerWeighModeMap.value = next;
  }

  function onCategorySelect(keys: KeyType[]) {
    selectedCategoryKeys.value = keys?.length ? keys : [TREE_ALL];
    reloadTable();
  }

  function onExpandedKeysChange(keys: KeyType[]) {
    expandedCategoryKeys.value = keys?.length ? keys : [TREE_ALL];
  }

  function handleCategoryVisibilityChange() {
    const key = selectedCategoryKeys.value[0];
    if (!key || key === TREE_ALL) {
      syncExpandedCategoryKeys();
      reloadTable();
      return;
    }
    const keyStr = String(key);
    const hidden = hiddenCategoryIdSet.value;
    const major = allMajorCategories.value.find((item) => item.id === keyStr);
    if (major) {
      const hasVisibleMinor = major.minors.some((minor) => !hidden.has(String(minor.id)));
      if (!hasVisibleMinor) {
        selectedCategoryKeys.value = [TREE_ALL];
      }
    } else if (hidden.has(keyStr)) {
      selectedCategoryKeys.value = [TREE_ALL];
    }
    syncExpandedCategoryKeys();
    reloadTable();
  }

  async function resolveKindForMaterial(material: Recordable, weighMode?: string) {
    const minorId = material?.minorCategoryId ? String(material.minorCategoryId) : '';
    const minorName = material?.minorCategoryId_dictText || '';
    if (!minorId) {
      return resolveMixingMaterialKindForPicker(weighMode, false, minorName);
    }
    if (categoryRubberMap.value[minorId] === undefined) {
      try {
        const cat = await defHttp.get<Recordable>({ url: '/sys/category/queryById', params: { id: minorId } });
        categoryRubberMap.value[minorId] = cat?.isRubber === '1' || cat?.isRubber === 1;
      } catch {
        categoryRubberMap.value[minorId] = false;
      }
    }
    return resolveMixingMaterialKindForPicker(
      weighMode,
      categoryRubberMap.value[minorId] ? '1' : '0',
      minorName,
    );
  }

  async function handleOk() {
    const keys = (getSelectRowKeys?.() || []) as string[];
    let row = selectedRow.value || ((getSelectRows?.() || []) as Recordable[])[0];
    if (!row && keys.length) {
      try {
        const raw = await queryMixerById({ id: keys[0] });
        row = (raw as any)?.id != null ? raw : (raw as any)?.result;
      } catch {
        // ignore
      }
    }
    if (!row?.id) {
      createMessage.warning('请选择一条密炼物料');
      return;
    }
    const weighMode = getPickerWeighMode(row.id);
    const payload: Recordable = { ...row, pickerWeighMode: weighMode };
    const materialKind = await resolveKindForMaterial(row, weighMode);
    applyMixingMaterialFromSelection(payload, row, materialKind);
    emit('select', payload);
    closeModal();
  }
</script>

<style lang="less" scoped>
  .mixing-material-picker {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-height: 520px;
  }

  .mixing-material-picker-toolbar {
    display: flex;
    align-items: center;
    gap: 8px;
  }

  .mixing-material-picker-body {
    display: flex;
    gap: 12px;
    min-height: 480px;
  }

  .mixing-material-picker-sider {
    width: 240px;
    flex-shrink: 0;
    border: 1px solid var(--border-color-base, #f0f0f0);
    border-radius: 4px;
    padding: 8px;
    overflow: auto;
  }

  .mixing-material-picker-sider-title {
    font-weight: 600;
    margin-bottom: 8px;
  }

  .mixing-material-picker-main {
    flex: 1;
    min-width: 0;
  }

  .mixing-material-picker-weigh-mode {
    min-width: 108px;
  }
</style>

<style lang="less">
  /* 下拉挂到 body，避免表格 overflow 裁剪；层级高于 Modal */
  .mixing-material-picker-weigh-mode-dropdown {
    z-index: 2100 !important;
  }
</style>
