<script setup lang="ts">
import { reactive, ref, onMounted, toRaw } from 'vue';
import { PageContainer } from 'antdv-pro-layout';
import { Form, Modal, message } from 'ant-design-vue/lib';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import {
  backupDownload,
  backupFileList,
  backupLog,
  exportLog,
  getFtpLogSet,
  getLogSet,
  getRemoteOut,
  updateFtpLogSet,
  updateLogSet,
  updateRemoteOut,
} from '@/api/logManage/logSet';
import { regExpIPv4 } from '@/utils/regular-utils';
import useDictStore from '@/store/modules/dict';
import useI18n from '@/hooks/useI18n';
import saveAs from 'file-saver';
import { writeSheet } from '@/utils/execl-utils';
const { getDict } = useDictStore();
const { t } = useI18n();

/**对象信息状态类型 */
type ModalStateType = {
  /**标题 */
  title: string;
  /**表单数据 */
  from: Record<string, any>;
  /**表单数据 loading */
  fromLoading: boolean;
  /**确定按钮 loading */
  confirmLoading: boolean;
};

/**日志设置信息状态 */
let logSetState: ModalStateType = reactive({
  title: '日志设置',
  from: {
    logDuration: 15,
    logCapacity: 10,
  },
  fromLoading: true,
  confirmLoading: true,
});

/**日志设置信息内表单属性和校验规则 */
const logSetStateFrom = Form.useForm(
  logSetState.from,
  reactive({
    logDuration: [
      {
        required: true,
        trigger: 'blur',
        message: '请输入日志保存时间，最少15天',
      },
    ],
    logCapacity: [
      {
        required: true,
        message: '请输入日志最大容量，最小10MB',
      },
    ],
  })
);

/**日志设置保存 */
function fnFormLogSetFinish() {
  logSetStateFrom.validate().then(() => {
    logSetState.confirmLoading = true;
    const from = toRaw(logSetState.from);
    updateLogSet({
      logDuration: from.logDuration,
      logCapacity: from.logCapacity,
    })
      .then(res => {
        if (res.code === RESULT_CODE_SUCCESS && res.data > 0) {
          message.success(`日志设置保存成功`, 3);
        } else {
          message.warning(`日志设置无变更`, 3);
        }
      })
      .finally(() => {
        logSetState.confirmLoading = false;
      });
  });
}

/**FTP日志对象信息状态 */
let ftpState: ModalStateType = reactive({
  title: 'FTP日志上报接口设置',
  from: {
    agreement: 'ftp',
    directory: '',
    ftpLog: 12,
    toIp: '',
  },
  fromLoading: true,
  confirmLoading: true,
});

/**FTP日志对象信息内表单属性和校验规则 */
const ftpStateFrom = Form.useForm(
  ftpState.from,
  reactive({
    toIp: [
      {
        required: true,
        pattern: regExpIPv4,
        message: '请输入对端IP地址',
      },
    ],
    directory: [
      {
        required: true,
        trigger: 'blur',
        message: '请输入对端文件目录',
      },
    ],
    ftpLog: [
      {
        required: true,
        trigger: 'blur',
        message: '请输入日志生成周期，最小12小时',
      },
    ],
  })
);

/**FTP日志对象保存 */
function fnFormFTPFinish() {
  ftpStateFrom.validate().then(() => {
    logSetState.confirmLoading = true;
    const from = toRaw(ftpState.from);
    updateFtpLogSet(from)
      .then(res => {
        if (res.code === RESULT_CODE_SUCCESS) {
          message.success(`FTP日志设置保存成功`, 3);
        } else {
          message.warning(`FTP日志设置无变更`, 3);
        }
      })
      .finally(() => {
        logSetState.confirmLoading = false;
      });
  });
}

/**日志远程输出对象信息状态 */
let remoteOutState: ModalStateType = reactive({
  title: '日志远程输出',
  from: {
    logIp: '',
    logDirectory: '',
  },
  fromLoading: true,
  confirmLoading: true,
});

/**日志远程输出对象信息内表单属性和校验规则 */
const remoteOutStateFrom = Form.useForm(
  remoteOutState.from,
  reactive({
    logIp: [
      {
        required: true,
        pattern: regExpIPv4,
        message: '请输入远程IP地址',
      },
    ],
    logDirectory: [
      {
        required: true,
        trigger: 'blur',
        message: '请输入远程日志目录',
      },
    ],
  })
);

/**日志远程输出对象保存 */
function fnFormRemoteOutFinish() {
  remoteOutStateFrom.validate().then(() => {
    remoteOutState.confirmLoading = true;
    const from = toRaw(remoteOutState.from);
    updateRemoteOut(from)
      .then(res => {
        if (res.code === RESULT_CODE_SUCCESS) {
          message.success(`日志远程输出设置保存成功`, 3);
        } else {
          message.warning(`日志远程输出设置无变更`, 3);
        }
      })
      .finally(() => {
        remoteOutState.confirmLoading = false;
      });
  });
}

/**字典数据 */
let dict: {
  /**操作日志操作类型 */
  operationLogType: DictType[];
} = reactive({
  operationLogType: [],
});

/**日志范围开始结束时间 */
let queryRangePicker = ref<[string, string]>(['', '']);

/**开始结束时间选择对应修改 */
function fnRangePickerChange(_: any, item: any) {
  logOutState.from.beginTime = item[0];
  logOutState.from.endTime = item[1];
}

/**日志导出对象信息状态 */
let logOutState: ModalStateType = reactive({
  title: '日志导出',
  from: {
    logType: 'security_log',
    opType: 'View',
    beginTime: '',
    endTime: '',
  },
  fromLoading: false,
  confirmLoading: false,
});

/**日志导出对象信息内表单属性和校验规则 */
const logOutStateFrom = Form.useForm(
  logOutState.from,
  reactive({
    endTime: [
      {
        required: true,
        message: '请输入日志时间范围',
      },
    ],
  })
);

/**日志导出对象保存 */
function fnFormLogOutFinish() {
  logOutStateFrom.validate().then(() => {
    logOutState.confirmLoading = true;
    const from = toRaw(logOutState.from);
    const key = 'exportLog';
    message.loading({ content: t('common.loading'), key });
    exportLog(from)
      .then(res => {
        if (res.code === RESULT_CODE_SUCCESS) {
          message.success({
            content: `已完成导出`,
            key,
            duration: 3,
          });
          writeSheet(res.data, from.logType).then(fileBlob =>
            saveAs(fileBlob, `${from.logType}_${Date.now()}.xlsx`)
          );
        } else {
          message.error({
            content: `${res.msg}`,
            key,
            duration: 3,
          });
        }
      })
      .finally(() => {
        logOutState.confirmLoading = false;
      });
  });
}

/**日志备份对象信息状态 */
let backState: ModalStateType = reactive({
  title: '日志备份',
  from: {
    logType: 'security_log',
    backFileTree: [],
  },
  fromLoading: true,
  confirmLoading: true,
});

/**日志备份对象保存 */
function fnFormBackFinish() {
  Modal.confirm({
    title: t('common.tipTitle'),
    content: `确认手动备份该日志类型数据到文件吗?`,
    onOk() {
      backState.confirmLoading = true;
      const key = 'backupLog';
      message.loading({ content: t('common.loading'), key });
      backupLog(backState.from.logType)
        .then(res => {
          if (res.code === RESULT_CODE_SUCCESS) {
            message.success({
              content: `手动备份执行成功记录数：${res.data}`,
              key,
              duration: 10,
            });
            fnBackFileList();
          } else {
            message.error({
              content: `${res.msg}`,
              key: key,
              duration: 3,
            });
          }
        })
        .finally(() => {
          backState.confirmLoading = false;
        });
    },
  });
}

/**日志手动备份文件列表 */
function fnBackFileList() {
  backupFileList().then(res => {
    if (res.code === RESULT_CODE_SUCCESS) {
      if (res.data.name === '') {
        backState.from.backFileTree = [];
      } else {
        backState.from.backFileTree = [res.data];
      }
      backState.fromLoading = false;
      backState.confirmLoading = false;
    }
  });
}

/**日志备份文件下载 */
function fnBackDownload(name: string, path: string) {
  Modal.confirm({
    title: t('common.tipTitle'),
    content: `确认下载该文件吗?`,
    onOk() {
      backState.confirmLoading = true;
      const key = 'backupDownload';
      message.loading({ content: t('common.loading'), key });
      backupDownload(path)
        .then(res => {
          if (res.code === RESULT_CODE_SUCCESS) {
            message.success({
              content: `已完成下载`,
              key,
              duration: 3,
            });
            saveAs(res.data, name);
          } else {
            message.error({
              content: `${res.msg}`,
              key,
              duration: 3,
            });
          }
        })
        .finally(() => {
          backState.confirmLoading = false;
        });
    },
  });
}

onMounted(() => {
  Promise.allSettled([
    getLogSet(),
    getFtpLogSet(),
    getRemoteOut(),
    getDict('operation_log_type'),
    fnBackFileList(),
  ]).then(resArr => {
    // 查询日志设置
    if (resArr[0].status === 'fulfilled') {
      const result = resArr[0].value;
      if (result.code === RESULT_CODE_SUCCESS) {
        logSetState.from = Object.assign(logSetState.from, result.data);
        logSetState.fromLoading = false;
        logSetState.confirmLoading = false;
      }
    }
    // 查询FTP日志设置
    if (resArr[1].status === 'fulfilled') {
      const result = resArr[1].value;
      if (result.code === RESULT_CODE_SUCCESS) {
        ftpState.from = Object.assign(ftpState.from, result.data);
        ftpState.fromLoading = false;
        ftpState.confirmLoading = false;
      }
    }
    // 查询日志远程输出设置
    if (resArr[2].status === 'fulfilled') {
      const result = resArr[2].value;
      if (result.code === RESULT_CODE_SUCCESS) {
        remoteOutState.from = Object.assign(remoteOutState.from, result.data);
        remoteOutState.fromLoading = false;
        remoteOutState.confirmLoading = false;
      }
    }
    // 初始字典数据 日志导出-操作日志
    if (resArr[3].status === 'fulfilled') {
      dict.operationLogType = resArr[3].value;
    }
  });
});
</script>

<template>
  <PageContainer>
    <a-row :gutter="16">
      <a-col :span="8">
        <!-- 日志设置 -->
        <a-card :title="logSetState.title" :loading="logSetState.fromLoading">
          <template #extra>
            <a-space :size="8" align="center">
              <a-button
                type="primary"
                :loading="logSetState.confirmLoading"
                @click.prevent="fnFormLogSetFinish"
              >
                <template #icon><SaveOutlined /></template>
                保存设置
              </a-button>
            </a-space>
          </template>
          <a-form
            name="logSetState.from"
            layout="horizontal"
            autocomplete="off"
            :label-col="{ span: 8 }"
          >
            <a-form-item
              label="日志保存时间(天)"
              name="logDuration"
              v-bind="logSetStateFrom.validateInfos.logDuration"
            >
              <a-input-number
                v-model:value="logSetState.from.logDuration"
                placeholder="15"
                :min="15"
              />
            </a-form-item>
            <a-form-item
              label="日志最大容量(MB)"
              name="logCapacity"
              v-bind="logSetStateFrom.validateInfos.logCapacity"
            >
              <a-input-number
                v-model:value="logSetState.from.logCapacity"
                placeholder="10"
                :min="10"
              />
            </a-form-item>
          </a-form>
        </a-card>

        <!-- 日志导出 -->
        <a-card
          :title="logOutState.title"
          :loading="logOutState.fromLoading"
          style="margin-top: 16px"
        >
          <template #extra>
            <a-space :size="8" align="center">
              <a-button
                type="primary"
                :loading="logOutState.confirmLoading"
                @click.prevent="fnFormLogOutFinish"
              >
                <template #icon><ExportOutlined /></template>
                导出
              </a-button>
            </a-space>
          </template>
          <a-form
            name="logOutState.from"
            layout="horizontal"
            autocomplete="off"
            :label-col="{ span: 5 }"
          >
            <a-form-item label="日志类型" name="logType">
              <a-select v-model:value="logOutState.from.logType">
                <a-select-option key="operation_log" value="operation_log">
                  操作日志
                </a-select-option>
                <a-select-option key="alarm_log" value="alarm_log">
                  告警日志
                </a-select-option>
                <a-select-option key="security_log" value="security_log">
                  安全日志
                </a-select-option>
              </a-select>
            </a-form-item>
            <a-form-item
              label="操作类型"
              name="opType"
              v-show="logOutState.from.logType === 'operation_log'"
            >
              <a-select
                v-model:value="logOutState.from.opType"
                placeholder="请选择操作类型"
                :options="dict.operationLogType"
              >
              </a-select>
            </a-form-item>
            <a-form-item
              label="时间范围"
              name="queryRangePicker"
              v-bind="logOutStateFrom.validateInfos.endTime"
            >
              <a-range-picker
                v-model:value="queryRangePicker"
                @change="fnRangePickerChange"
                allow-clear
                bordered
                show-time
                value-format="YYYY-MM-DD HH:mm:ss"
                format="YYYY-MM-DD HH:mm:ss"
                :placeholder="['记录开始', '记录结束']"
                style="width: 100%"
              ></a-range-picker>
            </a-form-item>
          </a-form>
        </a-card>
      </a-col>

      <a-col :span="8">
        <!-- FTP日志设置-->
        <a-card :title="ftpState.title" :loading="ftpState.fromLoading">
          <template #extra>
            <a-space :size="8" align="center">
              <a-button
                type="primary"
                :loading="ftpState.confirmLoading"
                @click.prevent="fnFormFTPFinish"
              >
                <template #icon><SaveOutlined /></template>
                保存设置
              </a-button>
            </a-space>
          </template>
          <a-form
            name="fTPState"
            layout="horizontal"
            autocomplete="off"
            :label-col="{ span: 8 }"
          >
            <a-form-item label="协议类型" name="agreement">
              <a-select v-model:value="ftpState.from.agreement">
                <a-select-option key="ftp" value="ftp">FTP</a-select-option>
                <a-select-option key="sftp" value="sftp">SFTP</a-select-option>
              </a-select>
            </a-form-item>
            <a-form-item
              label="对端IP地址"
              name="toIp"
              v-bind="ftpStateFrom.validateInfos.toIp"
            >
              <a-input
                v-model:value="ftpState.from.toIp"
                allow-clear
                placeholder="请输入对端IP地址"
              ></a-input>
            </a-form-item>
            <a-form-item
              label="对端文件目录"
              name="directory"
              v-bind="ftpStateFrom.validateInfos.directory"
            >
              <a-input
                v-model:value="ftpState.from.directory"
                allow-clear
                placeholder="请输入对端文件目录"
              ></a-input>
            </a-form-item>
            <a-form-item
              label="日志生成周期(小时)"
              name="ftpLog"
              v-bind="ftpStateFrom.validateInfos.ftpLog"
            >
              <a-input-number
                v-model:value="ftpState.from.ftpLog"
                placeholder="12"
                :min="12"
              />
            </a-form-item>
          </a-form>
        </a-card>
      </a-col>

      <a-col :span="8">
        <!-- 日志远程输出设置 -->
        <a-card
          :title="remoteOutState.title"
          :loading="remoteOutState.fromLoading"
        >
          <template #extra>
            <a-space :size="8" align="center">
              <a-button
                type="primary"
                :loading="remoteOutState.confirmLoading"
                @click.prevent="fnFormRemoteOutFinish"
              >
                <template #icon><SaveOutlined /></template>
                保存设置
              </a-button>
            </a-space>
          </template>
          <a-form
            name="remoteOutState.from"
            layout="horizontal"
            autocomplete="off"
            :label-col="{ span: 6 }"
          >
            <a-form-item
              label="远程IP地址"
              name="logIp"
              v-bind="remoteOutStateFrom.validateInfos.logIp"
            >
              <a-input
                v-model:value="remoteOutState.from.logIp"
                allow-clear
                placeholder="请输入远程IP地址"
              ></a-input>
            </a-form-item>
            <a-form-item
              label="远程日志目录"
              name="logDirectory"
              v-bind="remoteOutStateFrom.validateInfos.logDirectory"
            >
              <a-input
                v-model:value="remoteOutState.from.logDirectory"
                allow-clear
                placeholder="请输入远程日志目录"
              ></a-input>
            </a-form-item>
          </a-form>
        </a-card>

        <!-- 日志备份 -->
        <a-card
          :title="backState.title"
          :loading="backState.fromLoading"
          style="margin-top: 16px"
        >
          <template #extra>
            <a-space :size="8" align="center">
              <a-button
                type="primary"
                :loading="backState.confirmLoading"
                @click.prevent="fnFormBackFinish"
              >
                <template #icon><CloudServerOutlined /></template>
                备份
              </a-button>
            </a-space>
          </template>
          <a-form name="backState.from" layout="horizontal" autocomplete="off">
            <a-form-item label="日志类型" name="logType">
              <a-select v-model:value="backState.from.logType">
                <a-select-option key="operation_log" value="operation_log">
                  操作日志
                </a-select-option>
                <a-select-option key="alarm_log" value="alarm_log">
                  告警日志
                </a-select-option>
                <a-select-option key="security_log" value="security_log">
                  安全日志
                </a-select-option>
              </a-select>
            </a-form-item>
            <a-form-item
              label="备份文件"
              name="backFileTree"
              v-show="backState.from.backFileTree.length > 0"
            >
              <a-directory-tree
                :tree-data="backState.from.backFileTree"
                :field-names="{ children: 'items', title: 'name', key: 'path' }"
              >
                <template #title="{ isDir, name, path }">
                  <span>{{ name }}</span>
                  <span
                    class="backFile-download"
                    v-if="!isDir"
                    @click.prevent="fnBackDownload(name, path)"
                  >
                    下载
                  </span>
                </template>
              </a-directory-tree>
            </a-form-item>
          </a-form>
        </a-card>
      </a-col>
    </a-row>
  </PageContainer>
</template>

<style lang="less" scoped>
.backFile-download {
  margin-left: 12px;
  color: #eb2f96;
  text-decoration: underline;
}
</style>
