<script setup lang="ts">
import { reactive, onMounted, toRaw } from 'vue';
import { message, Form, Upload } from 'ant-design-vue/lib';
import useI18n from '@/hooks/useI18n';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { NE_TYPE_LIST } from '@/constants/ne-constants';
import { ColumnsType } from 'ant-design-vue/lib/table';
import { installNeSoftware, listNeSoftware } from '@/api/ne/neSoftware';
import { parseDateToStr } from '@/utils/date-utils';
import { FileType } from 'ant-design-vue/lib/upload/interface';
import { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
import { uploadFileChunk } from '@/api/tool/file';
import { stepState } from '../hooks/useStep';
const { t } = useI18n();

/**表格字段列 */
let tableColumns: ColumnsType = [
  {
    title: t('common.rowId'),
    dataIndex: 'id',
    align: 'left',
    width: 50,
  },
  {
    title: 'neType',
    dataIndex: 'neType',
    align: 'left',
    width: 100,
  },
  {
    title: 'name',
    dataIndex: 'name',
    key: 'name',
    align: 'left',
    width: 300,
  },
  {
    title: 'version',
    dataIndex: 'version',
    align: 'left',
    width: 100,
  },
  {
    title: 'description',
    dataIndex: 'description',
    key: 'description',
    align: 'left',
    ellipsis: true,
  },
  {
    title: 'createTime',
    dataIndex: 'createTime',
    align: 'left',
    width: 150,
    customRender(opt) {
      if (!opt.value) return '';
      return parseDateToStr(+opt.value);
    },
  },
];

/**表格分页器参数 */
let tablePagination = reactive({
  /**当前页数 */
  current: 1,
  /**每页条数 */
  pageSize: 10,
  /**默认的每页条数 */
  defaultPageSize: 10,
  /**指定每页可以显示多少条 */
  pageSizeOptions: ['10', '20', '50', '100'],
  /**只有一页时是否隐藏分页器 */
  hideOnSinglePage: false,
  /**是否可以快速跳转至某页 */
  showQuickJumper: true,
  /**是否可以改变 pageSize */
  showSizeChanger: true,
  /**数据总数 */
  total: 0,
  showTotal: (total: number) => t('common.tablePaginationTotal', { total }),
  onChange: (page: number, pageSize: number) => {
    tablePagination.current = page;
    tablePagination.pageSize = pageSize;
    tableState.queryParams.pageNum = page;
    tableState.queryParams.pageSize = pageSize;
    fnGetList();
  },
});

/**表格状态类型 */
type TabeStateType = {
  /**查询参数 */
  queryParams: Record<string, any>;
  /**加载等待 */
  loading: boolean;
  /**记录数据 */
  data: object[];
  /**勾选记录 */
  selectedRowKeys: (string | number)[];
};

/**表格状态 */
let tableState: TabeStateType = reactive({
  queryParams: {
    neType: '',
    pageNum: 1,
    pageSize: 10,
  },
  loading: false,
  data: [],
  selectedRowKeys: [],
});

/**表格多选 */
function fnTableSelectedRowKeys(
  keys: (string | number)[],
  selectedRows: any[]
) {
  tableState.selectedRowKeys = keys;
  // 选择的表单数据填充
  const row = selectedRows[0];
  installState.from.neType = row.neType;
  installState.from.name = row.name;
  installState.from.path = row.path;
  installState.from.version = row.version;
  installState.from.description = row.description;
}

/**查询列表, pageNum初始页数 */
function fnGetList(pageNum?: number) {
  if (tableState.loading) return;
  tableState.loading = true;
  if (pageNum) {
    tableState.queryParams.pageNum = pageNum;
  }
  listNeSoftware(toRaw(tableState.queryParams)).then(res => {
    if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
      // 取消勾选
      if (tableState.selectedRowKeys.length > 0) {
        tableState.selectedRowKeys = [];
      }
      tablePagination.total = res.total;
      // 遍历处理资源情况数值
      tableState.data = res.rows;
    }
    tableState.loading = false;
  });
}

/**安装对象信息状态类型 */
type InstallStateType = {
  /**步骤 */
  setp: 'pkg' | 'preinput' | 'log';
  /**步骤日志输出 */
  setpLog: string;
  /**文件操作类型 上传 or 选择 */
  optionType: 'upload' | 'option';
  /**表单数据 */
  from: {
    neType: string;
    neId: string;
    name: string;
    path: string;
    version: string;
    description: string;
  };
  /**确定按钮 loading */
  confirmLoading: boolean;
  /**上传文件 */
  uploadFiles: any[];
  /**预输入 */
  preinput: Record<string, any>;
};

/**安装对象信息状态 */
let installState: InstallStateType = reactive({
  setp: 'pkg',
  setpLog: '',
  optionType: 'upload',
  from: {
    neType: '',
    neId: '',
    name: '',
    path: '',
    version: '',
    description: '',
  },
  confirmLoading: false,
  uploadFiles: [],
  preinput: {
    // IMS
    pubIP: '192.168.5.57',
    mcc: '001',
    mnc: '01',
    priIP: '172.16.16.51',
    pisCSCF: 'true',
  },
});

/**
 * 表单修改网元类型
 */
function fnNeTypeChange(v: any) {
  tableState.queryParams.neType = v;
  if (installState.optionType === 'option') {
    fnGetList(1);
  }
}

/**
 * 表单修改文件操作类型
 */
function fnOptionTypeChange() {
  if (installState.optionType === 'upload') {
    installState.from.name = '';
    installState.from.path = '';
    installState.from.version = '';
    installState.from.description = '';
  }
  if (installState.optionType === 'option') {
    tableState.queryParams.neType = installState.from.neType;
    fnGetList(1);
  }
}

/**表单属性和校验规则 */
const installStateFrom = Form.useForm(
  installState.from,
  reactive({
    neType: [
      {
        required: true,
        min: 1,
        max: 32,
        message: t('views.configManage.softwareManage.neTypePlease'),
      },
    ],
    version: [
      {
        required: true,
        min: 1,
        max: 64,
        message: t('views.configManage.softwareManage.versionPlease'),
      },
    ],
    path: [
      {
        required: true,
        message: t('views.configManage.softwareManage.updateFilePlease'),
      },
    ],
  })
);

/**表单上传前检查或转换压缩 */
function fnBeforeUploadFile(file: FileType) {
  if (installState.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;
  }
  // 根据给定的软件名取版本号 ims-r2.2312.x-ub22.deb
  const matches = fileName.match(/([0-9.]+[0-9x]+)/);
  if (matches) {
    installState.from.version = matches[0];
  }
  const neTypeIndex = fileName.indexOf('-');
  if (neTypeIndex !== -1) {
    const neType = fileName.substring(0, neTypeIndex).toUpperCase();
    if (installState.from.neType !== neType) {
      message.error('请上传对应网元类型的安装包', 3);
      return Upload.LIST_IGNORE;
    }
  }
  return true;
}

/**表单上传文件 */
function fnUploadFile(up: UploadRequestOption) {
  // 发送请求
  const hide = message.loading(t('common.loading'), 0);
  installState.confirmLoading = true;
  uploadFileChunk(up.file as File, 5, 'software')
    .then(res => {
      if (res.code === RESULT_CODE_SUCCESS) {
        message.success('上传成功', 3);
        // 改为完成状态
        const file = installState.uploadFiles[0];
        file.percent = 100;
        file.status = 'done';
        // 预置到表单
        const { fileName, originalFileName } = res.data;
        installState.from.name = originalFileName;
        installState.from.path = fileName;
      } else {
        message.error(res.msg, 3);
      }
    })
    .finally(() => {
      hide();
      installState.confirmLoading = false;
    });
}

/**软件包检查 */
function fnRunCheck() {
  if (installState.confirmLoading) return;
  const hide = message.loading(t('common.loading'), 0);
  installStateFrom
    .validate()
    .then(() => {
      installState.setp = 'preinput';
    })
    .catch(e => {
      message.error(t('common.errorFields', { num: e.errorFields.length }), 3);
    })
    .finally(() => {
      hide();
      installState.confirmLoading = false;
    });
}

/**开始安装 */
function fnInstall() {
  if (installState.confirmLoading) return;
  installState.confirmLoading = true;
  const hide = message.loading(t('common.loading'), 0);
  const from = toRaw(installState.from);
  const preinput = toRaw(installState.preinput);
  installNeSoftware({
    software: from,
    preinput: preinput,
  })
    .then(res => {
      if (res.code === RESULT_CODE_SUCCESS) {
        installState.setp = 'log';
        installState.setpLog = res.data;
        message.success('软件安装成功', 3);
        // 记录当前步骤状态信息
        stepState.states[stepState.current] = {
          from: from,
          preinput: preinput,
        };
        stepState.stepNext = true;
      } else {
        message.error(res.msg, 3);
      }
    })
    .finally(() => {
      hide();
      installState.confirmLoading = false;
    });
}

/**重新安装 */
function fnInstallReset() {
  installState.setp = 'pkg';
  installState.optionType = 'option';
}

onMounted(() => {
  // 读取步骤：网元信息
  const stepPrevFrom = stepState.states[1];
  if (stepPrevFrom && stepPrevFrom.from) {
    installState.from.neType = stepPrevFrom.from.neType;
    installState.from.neId = stepPrevFrom.from.neId;
  }
});
</script>

<template>
  <a-form
    name="installStateFrom"
    layout="horizontal"
    :label-col="{ span: 3 }"
    :wrapper-col="{ span: 8 }"
    :label-wrap="true"
  >
    <div>---- 安装软件包</div>

    <template v-if="installState.setp === 'pkg'">
      <a-form-item
        :label="t('views.configManage.softwareManage.neType')"
        name="neType"
        v-bind="installStateFrom.validateInfos.neType"
      >
        <a-auto-complete
          v-model:value="installState.from.neType"
          :disabled="true"
          :options="NE_TYPE_LIST.map(v => ({ value: v }))"
          @change="fnNeTypeChange"
        >
          <a-input
            allow-clear
            :placeholder="t('common.inputPlease')"
            :maxlength="32"
            :disabled="true"
          >
            <template #prefix>
              <a-tooltip placement="topLeft">
                <template #title>
                  {{ t('views.configManage.neManage.neTypeTip') }}
                </template>
                <InfoCircleOutlined style="color: rgba(0, 0, 0, 0.45)" />
              </a-tooltip>
            </template>
          </a-input>
        </a-auto-complete>
      </a-form-item>

      <a-form-item label="软件来源" name="optionType">
        <a-radio-group
          v-model:value="installState.optionType"
          button-style="solid"
          @change="fnOptionTypeChange"
          :disabled="installState.confirmLoading"
        >
          <a-radio-button value="upload">新上传</a-radio-button>
          <a-radio-button value="option">已上传</a-radio-button>
        </a-radio-group>
      </a-form-item>

      <!-- 重新上传 -->
      <template v-if="installState.optionType === 'upload'">
        <a-form-item
          :label="t('views.configManage.softwareManage.version')"
          name="version"
          v-bind="installStateFrom.validateInfos.version"
        >
          <a-input
            v-model:value="installState.from.version"
            allow-clear
            :placeholder="t('views.configManage.softwareManage.versionPlease')"
          ></a-input>
        </a-form-item>
        <a-form-item
          :label="t('views.configManage.softwareManage.updateComment')"
          name="description"
          v-bind="installStateFrom.validateInfos.description"
        >
          <a-textarea
            v-model:value="installState.from.description"
            :auto-size="{ minRows: 1, maxRows: 4 }"
            :maxlength="500"
            :show-count="true"
            :placeholder="
              t('views.configManage.softwareManage.updateCommentPlease')
            "
          />
        </a-form-item>
        <a-form-item
          :label="t('views.configManage.softwareManage.updateFile')"
          name="file"
          v-bind="installStateFrom.validateInfos.path"
        >
          <a-upload
            name="file"
            v-model:file-list="installState.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="installState.confirmLoading"
          >
            <a-button type="default" :disabled="installState.confirmLoading">
              {{ t('views.configManage.softwareManage.selectFile') }}
            </a-button>
          </a-upload>
        </a-form-item>
      </template>

      <!-- 选择已上传 -->
      <template v-if="installState.optionType === 'option'">
        <a-form-item label="选择记录" name="option" :wrapper-col="{ span: 24 }">
          <a-table
            class="table"
            row-key="id"
            :columns="tableColumns"
            :loading="tableState.loading"
            :data-source="tableState.data"
            :pagination="tablePagination"
            size="small"
            :scroll="{ x: tableColumns.length * 100, y: '400px' }"
            :row-selection="{
              type: 'radio',
              columnWidth: '48px',
              selectedRowKeys: tableState.selectedRowKeys,
              onChange: fnTableSelectedRowKeys,
            }"
          >
            <template #bodyCell="{ column, record }">
              <template v-if="column.key === 'name'">
                <a-tooltip placement="topLeft">
                  <template #title>{{ record.path }}</template>
                  <div style="cursor: pointer">{{ record.name }}</div>
                </a-tooltip>
              </template>
              <template v-if="column.key === 'description'">
                <a-tooltip placement="topLeft">
                  <template #title>{{ record.description }}</template>
                  <div style="cursor: pointer">{{ record.description }}</div>
                </a-tooltip>
              </template>
            </template>
          </a-table>
        </a-form-item>
      </template>

      <a-form-item :wrapper-col="{ span: 14, offset: 3 }">
        <a-button
          type="primary"
          html-type="submit"
          @click="fnRunCheck()"
          :loading="installState.confirmLoading"
        >
          安装检查
        </a-button>
      </a-form-item>
    </template>

    <div>--- 安装前预输入</div>

    <template v-if="installState.setp === 'preinput'">
      <a-form-item
        name="info"
        label="安装前预输入"
        :label-col="{ span: 3 }"
        :label-wrap="true"
      >
        <div style="align-items: center">-----</div>
      </a-form-item>

      <!-- IMS 预输入 -->
      <template v-if="installState.from.neType === 'IMS'">
        <a-form-item label="P/I/S-CSCF Config" name="pisCSCF">
          <a-input
            v-model:value="installState.preinput.pisCSCF"
            allow-clear
            placeholder="P/I/S-CSCF Config"
          ></a-input>
        </a-form-item>
        <a-form-item label="modipplmn IP" name="pubIP">
          <a-input
            v-model:value="installState.preinput.pubIP"
            allow-clear
            placeholder="IMS modipplmn IP"
          ></a-input>
        </a-form-item>
        <a-form-item label="modipplmn mcc" name="mcc">
          <a-input
            v-model:value="installState.preinput.mcc"
            allow-clear
            placeholder="IMS modipplmn mcc"
          ></a-input>
        </a-form-item>
        <a-form-item label="modipplmn mnc" name="mnc">
          <a-input
            v-model:value="installState.preinput.mnc"
            allow-clear
            placeholder="IMS modipplmn mnc"
          ></a-input>
        </a-form-item>
        <a-form-item label="modintraip priIP" name="priIP">
          <a-input
            v-model:value="installState.preinput.priIP"
            allow-clear
            placeholder="IMS modintraip priIP"
          ></a-input>
        </a-form-item>
      </template>

      <a-form-item :wrapper-col="{ span: 14, offset: 3 }">
        <a-button
          type="primary"
          html-type="submit"
          @click="fnInstall()"
          :loading="installState.confirmLoading"
        >
          开始安装
        </a-button>
      </a-form-item>
    </template>

    <div>---- 安装进行信息</div>

    <template v-if="installState.setp === 'log'">
      <a-form-item
        name="info"
        label="安装日志"
        :label-col="{ span: 3 }"
        :wrapper-col="{ span: 24 }"
        :label-wrap="true"
      >
        <TerminalText
          id="installLog"
          :rows="28"
          :value="installState.setpLog"
        ></TerminalText>
      </a-form-item>

      <a-form-item :wrapper-col="{ span: 14, offset: 3 }">
        <a-button
          type="primary"
          html-type="submit"
          @click="fnInstallReset()"
          :loading="installState.confirmLoading"
        >
          返回重新选择安装
        </a-button>
      </a-form-item>
    </template>
  </a-form>
</template>

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