<template>
  <div class="guns-layout">
    <div class="guns-layout-content" style="padding: 12px 16px">
      <div class="guns-layout">
        <div class="guns-layout-content-header" style="padding: 8px 0; height: auto">
          <a-steps :current="currentStep">
            <a-step title="上传Excel" />
            <a-step title="Excel转化图片" />
            <a-step title="AI解析业务" />
            <a-step title="生成完成" />
          </a-steps>
        </div>
        <div class="guns-layout-content-application" style="gap: 16px; position: relative">
          <template v-if="[0, 1].includes(currentStep)">
            <div class="content-l">
              <div class="content-title">上传Excel</div>
              <div class="content-upload">
                <a-upload-dragger
                  v-model:fileList="fileList"
                  :showUploadList="false"
                  accept=".xlsx,.xls"
                  :before-upload="beforeUploadHandle"
                  :maxCount="1"
                  :disabled="currentStep == 0 ? false : true"
                >
                  <div class="upload-content">
                    <cloud-upload-outlined class="upload-icon" />
                    <div class="upload-dian">点击或拖拽文件或文件夹到此处上传</div>
                    <div class="upload-tool">仅支持 ExceL，文件大小不超过 50MB。</div>
                  </div>
                </a-upload-dragger>
              </div>
              <div class="content-file-list" v-if="fileList?.length > 0">
                <div class="content-file-list-title">文档:</div>
                <div class="content-file-list-item" v-for="(item, index) in fileList" :key="index">
                  {{ index + 1 }}.
                  <img src="@/assets/images/excel-doc.svg" alt="" />
                  {{ item.name }}
                  <span class="file-size">{{ getKb(item?.size) }}kb</span>
                  <span style="display: inline-block" v-if="currentStep == 0">
                    <icon-font
                      iconClass="icon-opt-shanchu"
                      font-size="20px"
                      color="#60666b"
                      title="删除"
                      @click="removeFileList"
                    ></icon-font>
                  </span>
                </div>
              </div>
              <div class="content-btn">
                <a-space :size="16">
                  <a-button class="border-radius" v-if="currentStep != 0" @click="preClick">上一步</a-button>
                  <a-button type="primary" class="border-radius" :disabled="stepNextBtnDisabled" @click="nextClick">下一步</a-button>
                </a-space>
              </div>
            </div>
            <div class="content-r">
              <template v-if="currentStep == 0">
                <div class="content-r-title">说明:</div>
                <div class="content-r-describe">1. 上传的Excel文件程序会调用AI模型进行视觉解析。</div>
                <div class="content-r-describe">2. 请确保Excel文件的文字没有被遮挡，否会影响解析效果。如下为一个错误示例:</div>
                <div class="content-r-img">
                  <img src="@/assets/images/excel-init-error.png" alt="" />
                </div>
              </template>
              <template v-if="currentStep == 1">
                <div class="content-r-img">
                  <img :src="pngUrl" alt="" v-if="pngFileId" />
                  <div class="content-r-img-loading" v-else>
                    <a-spin size="large" :delay="100"></a-spin>
                    <div class="content-r-img-loading-title">解析中</div>
                    <div class="content-r-img-loading-remark">程序会将Excel转化成图片，提供给AI使用</div>
                  </div>
                </div>
              </template>
            </div>
          </template>
          <template v-if="[2, 3].includes(currentStep)">
            <div class="content-all step2" v-if="currentStep == 2">
              <div class="content-all-left">
                <a-spin size="large"></a-spin>
                <div class="content-all-title">分析中</div>
                <div class="content-all-remark">业务自动分析中，请耐心等候...</div>
                <div class="content-all-btns">
                  <a-space :size="16">
                    <a-button class="border-radius" @click="stopAnalysis" v-if="logId">停止分析</a-button>
                  </a-space>
                </div>
              </div>
              <div class="content-all-right">
                <div class="status-item" v-for="(sItem, sIndex) in step2LoadList" :key="sItem">
                  {{ sIndex + 1 }}.{{ sItem.name }}
                  <a-spin size="small" style="margin-top: 2px" v-if="sItem.loading"></a-spin>
                  <template v-if="sItem.key == 3020">
                    <a v-if="sItem.showDetail" @click="lookLog">详情</a>
                  </template>
                  <check-circle-filled class="status-item-right" v-if="sItem.show" />
                </div>
              </div>
            </div>
            <div class="content-all" v-if="currentStep == 3">
              <img src="@/assets/images/success.svg" alt="" v-if="parseStatus == 20" />
              <img src="@/assets/images/error.svg" alt="" v-if="parseStatus == 30" />
              <div class="content-all-title">{{ parseStatus == 20 ? '恭喜，生成完成' : '解析失败，请重试' }}</div>
              <div class="content-all-remark">生成内容已保存至业务下对应目录中 <a v-if="parseStatus == 30" @click="showError = true">查看错误日志</a></div>
              <div class="content-all-btns">
                <a-space :size="16">
                  <a-button class="border-radius" @click="preClick">上一步</a-button>
                  <a-button class="border-radius" type="primary" @click="lookDetail">{{
                    parseStatus == 20 ? '立即查看' : '查看日志'
                  }}</a-button>
                </a-space>
              </div>
            </div>
          </template>
        </div>
      </div>
    </div>

    <LoadingLog v-model:visible="showLog" v-if="showLog" :data="jsonData"/>
    <ErrorLog v-model:visible="showError" v-if="showError" :data="errorData"/>
  </div>
</template>

<script setup>
import { computed, ref, createVNode, watch, defineAsyncComponent } from 'vue';
import { ExcelInitApi } from '../../api/ExcelInitApi';
import { message, Modal } from 'ant-design-vue';
import { getToken } from '@/utils/token-util';
import { API_BASE_PREFIX } from '@/config/setting';
import { ExclamationCircleOutlined } from '@ant-design/icons-vue';
import { useRouter } from 'vue-router';
import { useXStream } from '@/utils/common/useXStream';

const LoadingLog = defineAsyncComponent(() => import('./loading-log.vue'));
const ErrorLog = defineAsyncComponent(() => import('./error-log.vue'));

const props = defineProps({
  businessId: String
});

const emits = defineEmits(['stopAnalysis']);

const { startStream, cancel, data, error, isLoading } = useXStream();

const router = useRouter();

const currentStep = ref(0);

const fileList = ref([]);

const excelFileId = ref('');

const pngFileId = ref('');

const logId = ref('');

const parseStatus = ref(10);

// 是否禁用下一步按钮
const stepNextBtnDisabled = computed(() => {
  if (currentStep.value == 0) {
    return fileList.value.length == 0 ? true : false;
  } else if (currentStep.value == 1) {
    return pngFileId.value ? false : true;
  }
  return false;
});

const pngUrl = computed(() => {
  if (pngFileId.value) {
    return `${API_BASE_PREFIX}/sysFileInfo/private/preview?fileId=${pngFileId.value}&token=${getToken()}`;
  }
});

const step2LoadList = ref([
  {
    key: 3000,
    name: '创建解析日志',
    show: false,
    loading: false
  },
  {
    key: 3010,
    name: '开始调用大模型解析图片',
    show: false,
    loading: false
  },
  {
    key: 3020,
    name: 'AI返回JSON推流',
    show: false,
    loading: false,
    showDetail: false
  },
  {
    key: 3021,
    name: 'AI返回JSON推流结束',
    show: false,
    loading: false
  },
  {
    key: 3030,
    name: '清空当前业务模型',
    show: false,
    loading: false
  },
  {
    key: 3040,
    name: '创建模型',
    show: false,
    loading: false
  },
  {
    key: 3050,
    name: '创建表单信息',
    show: false,
    loading: false
  },
  {
    key: 3060,
    name: '执行create table建表语句',
    show: false,
    loading: false
  },
  {
    key: 3070,
    name: '创建视图',
    show: false,
    loading: false
  }
]);

const jsonData = ref('');

const showLog = ref(false);

const errorData = ref('');

const showError = ref(false);

// 上传之前
const beforeUploadHandle = async file => {
  const isLt5M = file.size / 1024 / 1024 < 50;
  if (!isLt5M) {
    message.error('图片大小不能超过50MB!');
    return false;
  }
  fileList.value = [file];
  return false;
};

const removeFileList = () => {
  fileList.value = [];
};

const preClick = () => {
  if (currentStep.value == 3) {
    logId.value = '';
    step2LoadList.value.forEach(item => {
      item.loading = false;
      item.show = false;

      if (item.showDetail) {
        item.showDetail = false;
      }
    });
    currentStep.value = 1;
  } else {
    currentStep.value--;
  }
};

const nextClick = () => {
  if (currentStep.value == 0) {
    if (fileList.value.length == 0) return message.error('请上传Excel');
    currentStep.value++;
    pngFileId.value = '';
    excelFileId.value = '';
    const formData = new FormData();
    formData.append('file', fileList.value[0].originFileObj);
    setTimeout(() => {
      ExcelInitApi.parseExcelToPng(formData).then(res => {
        message.success(res.message);
        excelFileId.value = res.data.excelFileId;
        pngFileId.value = res.data.pngFileId;
      });
    }, 1000);
  } else if (currentStep.value == 1) {
    currentStep.value++;
    parseStatus.value = 10;
    let params = {
      businessId: props.businessId,
      pngFileId: pngFileId.value,
      excelFileId: excelFileId.value
    };
    startSSE(params);
  } else if (currentStep.value == 2) {
    currentStep.value++;
  }
};

const startSSE = async params => {
  try {
    const response = await fetch(`${API_BASE_PREFIX}/aiBusinessDesign/parseToBusinessFlux`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: getToken()
      },
      body: JSON.stringify({
        ...params
      })
    });
    const readableStream = response.body;
    if (response.status == 200) {
      await startStream({ readableStream });
    } else {
      let errorMessage = '';
      try {
        // 首先尝试解析为JSON
        const errorData = await response.json();
        errorMessage = errorData.message || errorData.error || JSON.stringify(errorData);
      } catch (jsonError) {
        // 如果JSON解析失败，尝试读取为纯文本
        try {
          errorMessage = await response.text();
        } catch (textError) {
          errorMessage = `Failed to read error details: ${textError.message}`;
        }
      }
      message.error(errorMessage);
      cancel();
    }
  } catch (err) {
    console.error('Fetch error:', err);
  }
};

const stopAnalysis = () => {
  Modal.confirm({
    title: '提示',
    content: '确定要停止分析当前Excel吗?',
    icon: createVNode(ExclamationCircleOutlined),
    maskClosable: true,
    onOk: async () => {
      const res = await ExcelInitApi.stopAiParse({ aiParseLogId: logId.value });
      message.success(res.message);
      emits('stopAnalysis');
    }
  });
};

const lookDetail = () => {
  if (parseStatus.value == 20) {
    router.push({
      path: '/mid/app/detail',
      query: {
        type: 'sheet'
      }
    });
  } else if (parseStatus.value == 30) {
    emits('stopAnalysis');
  }
};

const getKb = size => {
  let value = 0;
  if (size) {
    value = (size / 1024).toFixed(2);
  }
  return value;
};

const lookLog = () => {
  showLog.value = true;
}

watch(
  () => data.value,
  val => {
    if (data.value?.length) {
      let text = '';
      for (let index = 0; index < data.value.length; index++) {
        const chunk = data.value[index].data;
        try {
          let chunkJson = JSON.parse(chunk);
          const { code, attachmentObject } = chunkJson;
          // 报错
          if (code == -1) {
            message.error(chunkJson.message);
            errorData.value = chunkJson.message;
            parseStatus.value = 30;
            currentStep.value++;
            cancel();
          } else if (code == 3000) {
            // 创建解析日志
            step2LoadList.value[0].loading = true;
            logId.value = attachmentObject;
          } else if (code == 3010) {
            // 开始调用大模型解析图片
            step2LoadList.value[0].loading = false;
            step2LoadList.value[0].show = true;
            step2LoadList.value[1].loading = true;
          } else if (code == 3020) {
            // AI返回JSON推流
            step2LoadList.value[1].loading = false;
            step2LoadList.value[1].show = true;
            step2LoadList.value[2].loading = true;
            step2LoadList.value[2].showDetail = true;

            text += chunkJson.message;
          } else if (code == 3021) {
            // AI返回JSON推流结束
            step2LoadList.value[2].loading = false;
            step2LoadList.value[2].show = true;
            step2LoadList.value[3].loading = true;
          } else if (code == 3030) {
            // 清空当前业务模型
            step2LoadList.value[3].loading = false;
            step2LoadList.value[3].show = true;
            step2LoadList.value[4].loading = true;
          } else if (code == 3040) {
            // 创建模型
            step2LoadList.value[4].loading = false;
            step2LoadList.value[4].show = true;
            step2LoadList.value[5].loading = true;
          } else if (code == 3050) {
            // 创建表单信息
            step2LoadList.value[5].loading = false;
            step2LoadList.value[5].show = true;
            step2LoadList.value[6].loading = true;
          } else if (code == 3060) {
            // 执行create table建表语句
            step2LoadList.value[6].loading = false;
            step2LoadList.value[6].show = true;
            step2LoadList.value[7].loading = true;
          } else if (code == 3070) {
            // 创建视图
            step2LoadList.value[7].loading = false;
            step2LoadList.value[7].show = true;
            step2LoadList.value[8].loading = true;
          } else if (code == 101) {
            // 正当响应结束
            step2LoadList.value[8].loading = false;
            step2LoadList.value[8].show = true;
            parseStatus.value = 20;
            currentStep.value++;
          }
        } catch (error) {
          console.error('解析数据时出错:', error);
          cancel();
        }
      }

      jsonData.value = text;
    }
  },
  { deep: true }
);
</script>

<style scoped lang="less">
.guns-layout-content-header {
  font-weight: normal !important;

  :deep(.ant-steps-item-icon) {
    width: 28px;
    height: 28px;
    line-height: 28px;
    background-color: #f2f3f5;
    border-color: #f2f3f5;
    color: #898e91;
    font-size: 16px;
    font-style: normal;
    font-weight: 400;
  }
  :deep(.ant-steps-item-active .ant-steps-item-title) {
    color: #0f56d7;
    font-size: 16px;
    font-style: normal;
    font-weight: 400;
  }
  :deep(.ant-steps-item-process > .ant-steps-item-container > .ant-steps-item-icon) {
    background-color: #3f78df;
  }
}

.content-l,
.content-r {
  width: 50%;
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.content-l {
  .content-title {
    position: relative;
    padding-left: 10px;
    color: #60666b;
    font-size: 16px;
    font-style: normal;
    font-weight: 700;
    line-height: normal;

    &::before {
      position: absolute;
      content: '';
      width: 2px;
      height: 60%;
      top: 20%;
      left: 0;
      background-color: #6463ff;
    }
  }

  .content-upload {
    width: 100%;
    flex: 1 0 0;

    :deep(.ant-upload-drag) {
      background-color: #fff;
      border-radius: 6px;
    }
    :deep(.upload-content) {
      position: absolute;
      top: 50%;
      left: 50%;
      margin-top: -51px;
      margin-left: -125px;

      .anticon {
        font-size: 32px;
        color: #60666b;
      }
      .upload-dian {
        margin-top: 24px;
        color: #43505e;
        font-size: 14px;
        font-style: normal;
        font-weight: 400;
        line-height: normal;
      }
      .upload-tool {
        margin-top: 4px;
        color: #898e91;
        font-size: 14px;
        font-style: normal;
        font-weight: 400;
        line-height: normal;
      }
    }
  }
  .content-file-list {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-bottom: 24px;

    .content-file-list-title {
      color: #60666b;
      font-size: 16px;
      font-style: normal;
      font-weight: 400;
      line-height: normal;
    }

    .content-file-list-item {
      width: 100%;
      padding-left: 48px;
      color: #60666b;
      font-size: 16px;
      font-style: normal;
      font-weight: 400;
      line-height: normal;

      img {
        width: 16px;
        height: 16px;
      }

      .file-size {
        margin-right: 4px;
        margin-left: 4px;
        margin-top: 4px;
        color: #898e91;
        font-style: normal;
        font-weight: 400;
        line-height: normal;
      }
    }
  }
  .content-btn {
    padding: 4px 0 8px 0;
  }
}

.content-r {
  padding: 16px;
  border-radius: 6px;
  background: rgba(246, 246, 249, 0.85);
  overflow-y: auto;

  .content-r-title {
    color: #60666b;
    font-size: 16px;
    font-style: normal;
    font-weight: 700;
    line-height: normal;
  }

  .content-r-describe {
    color: #60666b;
    font-size: 16px;
    font-style: normal;
    font-weight: 400;
    line-height: normal;
  }

  .content-r-img {
    width: 100%;
    flex: 1 0 0;
    position: relative;

    img {
      width: 100%;
    }

    .content-r-img-loading {
      position: absolute;
      top: 50%;
      left: 50%;
      margin-top: -45px;
      margin-left: -147px;
      text-align: center;

      .content-r-img-loading-title {
        color: #60666b;
        font-size: 20px;
        font-style: normal;
        font-weight: 700;
        line-height: normal;
      }
      .content-r-img-loading-remark {
        color: #898e91;
        font-size: 16px;
        font-style: normal;
        font-weight: 400;
        line-height: normal;
      }
    }
  }
}

.content-all {
  position: absolute;
  text-align: center;
  top: 50%;
  left: 50%;
  margin-top: -121px;
  margin-left: -110px;

  .content-all-title {
    color: #60666b;
    font-size: 20px;
    font-style: normal;
    font-weight: 700;
    line-height: normal;
    margin: 8px 0;
  }
  .content-all-remark {
    color: #898e91;
    font-size: 16px;
    font-style: normal;
    font-weight: 400;
    line-height: normal;
  }
  .content-all-btns {
    margin-top: 40px;
  }
}

.step2 {
  display: flex;
  align-items: center;
  gap: 32px;
  margin-top: -151px;
  margin-left: -254px;

  .content-all-right {
    width: 254px;
    display: flex;
    padding: 16px;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    border-radius: 6px;
    background: rgba(246, 246, 249, 0.85);

    .status-item {
      width: 100%;
      display: flex;
      align-items: center;
      gap: 8px;
      color: #60666b;
      font-size: 16px;
      font-style: normal;
      font-weight: 400;
      line-height: normal;

      .status-item-right {
        font-size: 16px;
        color: #43c93e;
      }
    }
  }
}

.content-next-btn {
  position: absolute;
  bottom: 16px;
  right: 16px;
}
</style>
