<script setup lang="ts">
import { reactive, onMounted, toRaw, watch } from 'vue';
import { message, Form, Upload, notification } from 'ant-design-vue/lib';
import useI18n from '@/hooks/useI18n';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { NE_EXPAND_LIST, NE_TYPE_LIST } from '@/constants/ne-constants';
import { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
import {
  addNeSoftware,
  getNeSoftware,
  updateNeSoftware,
} from '@/api/ne/neSoftware';
import { FileType } from 'ant-design-vue/lib/upload/interface';
import { uploadFileChunk } from '@/api/tool/file';
const { t } = useI18n();
const emit = defineEmits(['ok', 'cancel', 'update:visible']);
const props = defineProps({
  visible: {
    type: Boolean,
    default: false,
  },
  editId: {
    type: String,
    default: '',
  },
});

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

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

/**对话框内表单属性和校验规则 */
const modalStateFrom = Form.useForm(
  modalState.from,
  reactive({
    neType: [
      {
        required: true,
        min: 1,
        max: 32,
        message: t('views.ne.common.neTypePlease'),
      },
    ],
    version: [
      {
        required: true,
        min: 1,
        max: 64,
        message: t('views.ne.neSoftware.versionPlease'),
      },
    ],
    path: [
      {
        required: true,
        message: t('views.ne.neSoftware.pathPlease'),
      },
    ],
  })
);

/**
 * 对话框弹出确认执行函数
 * 进行表达规则校验
 */
function fnModalOk() {
  if (modalState.confirmLoading) return;
  modalStateFrom
    .validate()
    .then(e => {
      modalState.confirmLoading = true;
      const hide = message.loading(t('common.loading'), 0);
      const from = toRaw(modalState.from);

      // 安装带依赖包
      if (modalState.uploadFilesDep.length > 0) {
        const depFiles = [];
        for (const depFile of modalState.uploadFilesDep) {
          if (depFile.status === 'done' && depFile.path) {
            depFiles.push(depFile.path);
          }
        }
        depFiles.push(from.path);
        from.path = depFiles.join(',');
      }

      const software = from.id ? updateNeSoftware(from) : addNeSoftware(from);
      software.then(res => {
        if (res.code === RESULT_CODE_SUCCESS) {
          message.success({
            content: t('common.operateOk'),
            duration: 3,
          });
          // 返回无引用信息
          emit('ok', JSON.parse(JSON.stringify(from)));
          fnModalCancel();
        } else {
          message.error({
            content: `${res.msg}`,
            duration: 3,
          });
        }
        hide();
        modalState.confirmLoading = false;
      });
    })
    .catch(e => {
      message.error(t('common.errorFields', { num: e.errorFields.length }), 3);
    });
}

/**
 * 对话框弹出关闭执行函数
 * 进行表达规则校验
 */
function fnModalCancel() {
  modalState.visibleByEdit = false;
  modalState.confirmLoading = false;
  modalStateFrom.resetFields();
  modalState.uploadFiles = [];
  modalState.uploadFilesDep = [];
  emit('cancel');
  emit('update:visible', 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.configManage.softwareManage.onlyAble', {
        fileText: '(.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_LIST.includes(neType)) {
    notification.warning({
      message: fileName,
      description: t('views.ne.neSoftware.fileCheckType'),
    });
    return Upload.LIST_IGNORE;
  }
  modalState.from.neType = neType;

  // 根据给定的软件名取版本号 ims-r2.2312.x-ub22.deb
  const matches = fileName.match(/([0-9.]+[0-9x]+)/);
  if (matches) {
    modalState.from.version = matches[0];
  }
  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;
        // 预置到表单
        const { fileName, originalFileName } = res.data;
        modalState.from.name = originalFileName;
        modalState.from.path = 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.configManage.softwareManage.onlyAble', {
        fileText: '(.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;
    });
}

/**
 * 对话框弹出显示为 新增或者修改
 * @param id id
 */
function fnModalVisibleByEdit(id?: string) {
  if (id) {
    const hide = message.loading(t('common.loading'), 0);
    getNeSoftware(id)
      .then(res => {
        if (res.code === RESULT_CODE_SUCCESS) {
          Object.assign(modalState.from, res.data);
          modalState.title = t('views.ne.neSoftware.uploadTitle');
          modalState.visibleByEdit = true;
        } else {
          message.error(res.msg, 3);
        }
      })
      .finally(() => {
        modalState.confirmLoading = false;
        hide();
      });

    return;
  }
  modalState.title = t('views.ne.neSoftware.uploadTitle');
  modalState.visibleByEdit = true;
}

/**监听是否显示，初始数据 */
watch(
  () => props.visible,
  val => {
    if (val) fnModalVisibleByEdit(props.editId);
  }
);

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

<template>
  <a-modal
    width="550px"
    :keyboard="false"
    :mask-closable="false"
    :visible="modalState.visibleByEdit"
    :title="modalState.title"
    :confirm-loading="modalState.confirmLoading"
    @ok="fnModalOk"
    @cancel="fnModalCancel"
  >
    <a-form
      name="modalStateFrom"
      layout="horizontal"
      :wrapper-col="{ span: 16 }"
      :label-col="{ span: 8 }"
      :labelWrap="true"
    >
      <template v-if="modalState.from.id === ''">
        <a-form-item
          :label="t('views.ne.neSoftware.path')"
          :help="t('views.ne.neSoftware.uploadFileName')"
          name="file"
          v-bind="modalStateFrom.validateInfos.path"
        >
          <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>

      <a-form-item
        :label="t('views.ne.common.neType')"
        name="neType"
        v-bind="modalStateFrom.validateInfos.neType"
      >
        <a-auto-complete
          v-model:value="modalState.from.neType"
          :options="NE_TYPE_LIST.map(v => ({ value: v }))"
          :disabled="modalState.from.id !== ''"
        >
          <a-input
            allow-clear
            :placeholder="t('common.inputPlease')"
            :maxlength="32"
            :disabled="modalState.from.id !== ''"
          >
          </a-input>
        </a-auto-complete>
      </a-form-item>

      <a-form-item
        :label="t('views.ne.neSoftware.version')"
        name="version"
        v-bind="modalStateFrom.validateInfos.version"
      >
        <a-input
          v-model:value="modalState.from.version"
          allow-clear
          :placeholder="t('common.inputPlease')"
        ></a-input>
      </a-form-item>

      <a-form-item :label="t('common.description')" name="description">
        <a-textarea
          v-model:value="modalState.from.description"
          :maxlength="500"
          :show-count="true"
          :placeholder="t('common.inputPlease')"
        />
      </a-form-item>
    </a-form>
  </a-modal>
</template>

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