<script setup lang="ts">
import { reactive, onMounted, toRaw, watch } from 'vue';
import { ProModal } from 'antdv-pro-modal';
import { message, Upload, notification } from 'ant-design-vue/es';
import type { UploadRequestOption } from 'ant-design-vue/es/vc-upload/interface';
import type { FileType, UploadFile } from 'ant-design-vue/es/upload/interface';
import useI18n from '@/hooks/useI18n';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { NE_TYPE_LIST, NE_EXPAND_LIST } from '@/constants/ne-constants';
import { addNeSoftware } from '@/api/ne/neSoftware';
import { uploadFileChunk } from '@/api/tool/file';
const { t } = useI18n();
const emit = defineEmits(['ok', 'cancel', 'update:open']);
const props = defineProps({
  open: {
    type: Boolean,
    default: false,
  },
  /**网元类型，指定上传 */
  neType: {
    type: String,
  },
});

/**网元支持 */
const NE_TYPE_EXP = NE_EXPAND_LIST.concat(NE_TYPE_LIST);

/**对话框对象信息状态类型 */
type ModalStateType = {
  /**新增框或修改框是否显示 */
  openByMoreFile: boolean;
  /**标题 */
  title: string;
  /**表单数据 */
  from: {
    neType: string;
    name: string;
    path: string;
    version: string;
    description: string;
  }[];
  /**确定按钮 loading */
  confirmLoading: boolean;
  /**上传文件 */
  uploadFiles: any[];
  /**上传文件-依赖包 */
  uploadFilesDep: any[];
};

/**对话框对象信息状态 */
let modalState: ModalStateType = reactive({
  openByMoreFile: false,
  title: '软件包文件',
  from: [],
  confirmLoading: false,
  uploadFiles: [],
  uploadFilesDep: [],
});

/**
 * 对话框弹出确认执行函数
 * 进行表达规则校验
 */
async function fnModalOk() {
  if (modalState.confirmLoading) return;
  if (modalState.uploadFiles.length < 1) {
    message.warning({
      content: t('views.ne.neSoftware.uploadNotFile'),
      duration: 3,
    });
    return;
  }
  // 处理上传文件过滤
  const uploadFiles = toRaw(modalState.uploadFiles);
  const from = toRaw(modalState.from);
  const expandFile: Record<string, string> = {};
  for (const item of uploadFiles) {
    if (item.status !== 'done' || !item.path) continue;
    const neSoftware = from.find(s => s.name === item.name);
    if (neSoftware && NE_TYPE_LIST.includes(neSoftware.neType)) {
      neSoftware.path = item.path;
    }
    if (neSoftware && NE_EXPAND_LIST.includes(neSoftware.neType)) {
      expandFile[neSoftware.neType] = item.path;
    }
  }

  // IMS拼接拓展包
  const ims = from.find(s => s.neType === 'IMS');
  if (ims) {
    const pkgArr = [];
    if (expandFile['ADB']) {
      pkgArr.push(expandFile['ADB']);
    }
    if (expandFile['KVDB']) {
      pkgArr.push(expandFile['KVDB']);
    }
    if (expandFile['RTPROXY']) {
      pkgArr.push(expandFile['RTPROXY']);
    }
    if (expandFile['MF']) {
      pkgArr.push(expandFile['MF']);
    }
    pkgArr.push(ims.path);
    ims.path = pkgArr.join(',');
  }
  // UDM拼接拓展包
  const udm = from.find(s => s.neType === 'UDM');
  if (udm && expandFile['ADB']) {
    udm.path = [expandFile['ADB'], udm.path].join(',');
  } else if (udm && expandFile['KVDB']) {
    udm.path = [expandFile['KVDB'], udm.path].join(',');
  }

  // 安装带依赖包-指定网元时
  if (props.neType && modalState.uploadFilesDep.length > 0) {
    const neInfo = from.find(s => s.neType === props.neType);
    if (neInfo) {
      const depFiles = [];
      for (const depFile of modalState.uploadFilesDep) {
        if (depFile.status === 'done' && depFile.path) {
          depFiles.push(depFile.path);
        }
      }
      depFiles.push(neInfo.path);
      neInfo.path = depFiles.join(',');
    }
  }

  // 开始添加到软件包数据
  const rows: any[] = [];
  modalState.confirmLoading = true;
  for (const item of from.filter(s => NE_TYPE_LIST.includes(s.neType))) {
    try {
      const res = await addNeSoftware(item);
      if (res.code === RESULT_CODE_SUCCESS) {
        rows.push(item);
      } else {
        message.error({
          content: `${item.neType} ${res.msg}`,
          duration: 3,
        });
      }
    } catch (error) {
      console.error(error);
    }
  }

  emit('ok', rows);
  fnModalCancel();
}

/**
 * 对话框弹出关闭执行函数
 * 进行表达规则校验
 */
function fnModalCancel() {
  modalState.openByMoreFile = false;
  modalState.confirmLoading = false;
  modalState.from = [];
  modalState.uploadFiles = [];
  modalState.uploadFilesDep = [];
  emit('cancel');
  emit('update:open', false);
}

/**表单上传前检查或转换压缩 */
function fnBeforeUploadFile(file: FileType) {
  if (modalState.confirmLoading) return false;
  const fileName = file.name;
  const suff = fileName.substring(fileName.lastIndexOf('.'));
  if (!['.deb', '.rpm'].includes(suff)) {
    message.error(
      t('views.ne.neSoftware.fileTypeNotEq', {
        txt: '(.deb、.rpm)',
      }),
      3
    );
    return Upload.LIST_IGNORE;
  }

  // 取网元类型判断是否支持
  let neType = '';
  const neTypeIndex = fileName.indexOf('-');
  if (neTypeIndex !== -1) {
    neType = fileName.substring(0, neTypeIndex).toUpperCase();
  }
  if (!NE_TYPE_EXP.includes(neType)) {
    notification.warning({
      message: fileName,
      description: t('views.ne.neSoftware.fileCheckType'),
    });
    return Upload.LIST_IGNORE;
  }
  // 根据给定的软件名取版本号 amf-r2.2404.xx-ub22.deb
  let version = '';
  const matches = fileName.match(/([0-9.]+[0-9x]+)/);
  if (matches) {
    version = matches[0];
  } else {
    notification.warning({
      message: fileName,
      description: t('views.ne.neSoftware.fileCheckVer'),
    });
    return Upload.LIST_IGNORE;
  }

  // 单网元上传
  if (props.neType && props.neType !== neType) {
    notification.warning({
      message: fileName,
      description: t('views.ne.neSoftware.fileTypeNotEq', {
        txt: props.neType,
      }),
    });
    return Upload.LIST_IGNORE;
  } else {
    // 多文件上传时检查是否有同类型网元包
    const hasItem = modalState.from.find(item => item.neType === neType);
    if (hasItem) {
      notification.warning({
        message: fileName,
        description: t('views.ne.neSoftware.fileTypeExists'),
      });
      return Upload.LIST_IGNORE;
    }
  }

  modalState.from.push({
    name: fileName,
    neType: neType,
    version: version,
    path: '', // 上传完成后提交注入
    description: '',
  });
  return true;
}

/**表单上传前删除 */
function fnBeforeRemoveFile(file: UploadFile) {
  const fileName = file.name;
  // 取网元类型判断是否支持
  let neType = '';
  const neTypeIndex = fileName.indexOf('-');
  if (neTypeIndex !== -1) {
    neType = fileName.substring(0, neTypeIndex).toUpperCase();
  }
  const idx = modalState.from.findIndex(item => item.neType === neType);
  modalState.from.splice(idx, 1);
  return true;
}

/**表单上传文件 */
function fnUploadFile(up: UploadRequestOption) {
  const uploadFile = modalState.uploadFiles.find(
    item => item.uid === (up.file as any).uid
  );
  if (!uploadFile) return;

  // 发送请求
  uploadFileChunk(up.file as File, 5, 'software')
    .then(res => {
      if (res.code === RESULT_CODE_SUCCESS) {
        // 改为完成状态
        uploadFile.percent = 100;
        uploadFile.status = 'done';
        uploadFile.path = res.data.fileName;
      } else {
        message.error(res.msg, 3);
      }
    })
    .catch(error => {
      uploadFile.percent = 0;
      uploadFile.status = 'error';
      uploadFile.response = error.message;
    })
    .finally(() => {
      modalState.confirmLoading = false;
    });
}

/**表单上传前检查或转换压缩-依赖包 */
function fnBeforeUploadFileDep(file: FileType) {
  if (modalState.confirmLoading) return false;
  const fileName = file.name;
  const suff = fileName.substring(fileName.lastIndexOf('.'));
  if (!['.deb', '.rpm'].includes(suff)) {
    message.error(
      t('views.ne.neSoftware.fileTypeNotEq', {
        txt: '(.deb、.rpm)',
      }),
      3
    );
    return Upload.LIST_IGNORE;
  }

  // 已存在同名文件
  const hasItem = modalState.uploadFilesDep.find(
    item => item.name === fileName
  );
  if (hasItem) {
    notification.warning({
      message: fileName,
      description: t('views.ne.neSoftware.fileNameExists'),
    });
    return Upload.LIST_IGNORE;
  }

  // 取网元类型判断是否支持
  let neType = '';
  const neTypeIndex = fileName.indexOf('-');
  if (neTypeIndex !== -1) {
    neType = fileName.substring(0, neTypeIndex).toUpperCase();
  }
  // 依赖包类型
  if (!NE_EXPAND_LIST.includes(neType)) {
    notification.warning({
      message: fileName,
      description: t('views.ne.neSoftware.fileCheckTypeDep'),
    });
    return Upload.LIST_IGNORE;
  }

  return true;
}

/**表单上传文件-依赖包 */
function fnUploadFileDep(up: UploadRequestOption) {
  const uploadFile = modalState.uploadFilesDep.find(
    item => item.uid === (up.file as any).uid
  );
  if (!uploadFile) return;

  // 发送请求
  uploadFileChunk(up.file as File, 5, 'software')
    .then(res => {
      if (res.code === RESULT_CODE_SUCCESS) {
        // 改为完成状态
        uploadFile.percent = 100;
        uploadFile.status = 'done';
        uploadFile.path = res.data.fileName;
      } else {
        message.error(res.msg, 3);
      }
    })
    .catch(error => {
      uploadFile.percent = 0;
      uploadFile.status = 'error';
      uploadFile.response = error.message;
    })
    .finally(() => {
      modalState.confirmLoading = false;
    });
}

/**监听是否显示，初始数据 */
watch(
  () => props.open,
  val => {
    if (val) {
      modalState.title = t('views.ne.neSoftware.uploadTitle');
      modalState.openByMoreFile = true;
    }
  }
);

onMounted(() => {});
</script>

<template>
  <ProModal
    :drag="true"
    :width="800"
    :keyboard="false"
    :mask-closable="false"
    :open="modalState.openByMoreFile"
    :title="modalState.title"
    :confirm-loading="modalState.confirmLoading"
    @ok="fnModalOk"
    @cancel="fnModalCancel"
  >
    <a-form
      name="modalStateFrom"
      layout="horizontal"
      :wrapper-col="{ span: 18 }"
      :label-col="{ span: 6 }"
      :labelWrap="true"
    >
      <template v-if="props.neType">
        <a-form-item :label="t('views.ne.common.neType')" name="type">
          <a-tag color="processing">
            {{ props.neType }}
          </a-tag>
        </a-form-item>

        <a-form-item
          :label="t('views.ne.neSoftware.path')"
          :help="t('views.ne.neSoftware.uploadFileName')"
          :required="true"
          :validate-on-rule-change="false"
          :validateTrigger="[]"
          name="file"
        >
          <a-upload
            name="file"
            v-model:file-list="modalState.uploadFiles"
            accept=".rpm,.deb"
            list-type="text"
            :max-count="1"
            :show-upload-list="{
              showPreviewIcon: false,
              showRemoveIcon: false,
              showDownloadIcon: false,
            }"
            :before-upload="fnBeforeUploadFile"
            :custom-request="fnUploadFile"
            :disabled="modalState.confirmLoading"
          >
            <a-button type="primary">
              <template #icon>
                <UploadOutlined />
              </template>
              {{ t('views.ne.neSoftware.upload') }}
            </a-button>
          </a-upload>
        </a-form-item>

        <a-form-item
          name="dep"
          :label="t('views.ne.neSoftware.dependFile')"
          :help="t('views.ne.neSoftware.dependFileTip')"
        >
          <a-upload
            name="file"
            v-model:file-list="modalState.uploadFilesDep"
            accept=".rpm,.deb"
            list-type="text"
            :multiple="true"
            :max-count="5"
            :show-upload-list="{
              showPreviewIcon: false,
              showRemoveIcon: true,
              showDownloadIcon: false,
            }"
            :before-upload="fnBeforeUploadFileDep"
            :custom-request="fnUploadFileDep"
            :disabled="modalState.confirmLoading"
          >
            <a-button type="dashed">
              <template #icon>
                <UploadOutlined />
              </template>
              {{ t('views.ne.neSoftware.upload') }}
            </a-button>
          </a-upload>
        </a-form-item>
      </template>

      <template v-else>
        <a-form-item :label="t('common.description')">
          {{
            t('views.ne.neSoftware.uploadBatchMax', {
              txt: NE_TYPE_EXP.length,
            })
          }}
          <br />
          {{ t('views.ne.neSoftware.uploadFileName') }}
        </a-form-item>
        <a-form-item
          :label="t('views.ne.neSoftware.path')"
          :required="true"
          :validate-on-rule-change="false"
          :validateTrigger="[]"
          name="file"
        >
          <a-upload
            name="file"
            v-model:file-list="modalState.uploadFiles"
            accept=".rpm,.deb"
            list-type="text"
            :multiple="true"
            :max-count="NE_TYPE_EXP.length"
            :show-upload-list="{
              showPreviewIcon: false,
              showRemoveIcon: true,
              showDownloadIcon: false,
            }"
            :remove="fnBeforeRemoveFile"
            :before-upload="fnBeforeUploadFile"
            :custom-request="fnUploadFile"
            :disabled="modalState.confirmLoading"
          >
            <a-button type="primary">
              <template #icon>
                <UploadOutlined />
              </template>
              {{ t('views.ne.neSoftware.upload') }}
            </a-button>
          </a-upload>
        </a-form-item>
      </template>
    </a-form>
  </ProModal>
</template>

<style lang="less" scoped></style>
