<template>
  <el-dialog
    custom-class="ai-question-create-dialog"
    :visible.sync="modalIsShow"
    fullscreen
    :close-on-click-modal="false"
    :close-on-press-escape="false"
    append-to-body
    :show-close="false"
    @opened="handleOpened"
    @close="handleClose"
  >
    <div slot="title" class="dialog-title-container box-justify">
      <div class="title-left">
        <span class="title-text">创建试题 - AI 命题</span>
        <span v-if="courseInfo.name && courseInfo.code" class="course-info">
          {{ courseInfo.name }} ({{ courseInfo.code }})
        </span>
      </div>
      <div>
        <el-button icon="el-icon-back" @click="close">返回</el-button>
      </div>
    </div>

    <div class="dialog-content-container">
      <div class="left-panel">
        <el-form
          ref="form"
          :model="formModel"
          :rules="rules"
          label-width="90px"
          class="form-container"
          :disabled="loading"
        >
          <el-form-item prop="questionType" label="选择题型">
            <el-button
              v-for="item in questionTypes"
              :key="item.id"
              :type="
                formModel.questionType === item.questionType &&
                formModel.questionTypeName === item.name
                  ? 'primary'
                  : 'default'
              "
              size="small"
              style="margin: 0 5px 6px"
              @click="switchType(item)"
              >{{ item.name }}</el-button
            >
          </el-form-item>

          <el-form-item prop="questionCount" label="出题数量">
            <el-input-number
              v-model="formModel.questionCount"
              :min="1"
              :max="10"
              :step="1"
              step-strictly
              :controls="false"
              disabled
            ></el-input-number>
          </el-form-item>

          <el-form-item
            v-if="isChoiceQuestion"
            prop="optionCount"
            label="选项个数"
          >
            <el-input-number
              v-model="formModel.optionCount"
              :min="2"
              :max="8"
              :step="1"
              step-strictly
              :controls="false"
            ></el-input-number>
          </el-form-item>

          <el-form-item
            v-if="courseInfo.outlineFilePath && courseOutlineParsed"
            label="教学大纲"
          >
            <div class="box-justify">
              <el-checkbox v-model="formModel.syllabus"
                >教学大纲pdf</el-checkbox
              >
            </div>
            <el-input
              v-if="formModel.syllabus"
              type="textarea"
              :rows="3"
              v-model="formModel.syllabusNotes"
              placeholder="请输入教学大纲补充说明"
            ></el-input>
          </el-form-item>

          <el-form-item label="选择知识点">
            <property-tree-select
              v-model="formModel.propertyIdList"
              :course-id="courseInfo.id"
              :disabled="loading"
              :style="{ width: '100%' }"
            ></property-tree-select>
            <el-input
              v-if="
                formModel.propertyIdList && formModel.propertyIdList.length > 0
              "
              v-model="formModel.knowledgeNotes"
              type="textarea"
              :rows="3"
              placeholder="请输入知识点补充说明"
              style="margin-top: 10px"
            ></el-input>
          </el-form-item>

          <el-form-item>
            <el-button
              type="primary"
              :loading="loading"
              @click="toBuildQuestion"
              >生成试题</el-button
            >
          </el-form-item>
        </el-form>
      </div>

      <div class="right-panel">
        <div class="sse-output-title">试题预览</div>
        <div class="sse-output-container" ref="sseOuiputContainerRef">
          <template v-if="aiThinkingResult">
            <div
              class="sse-thinking-title"
              @click="thinkVisible = !thinkVisible"
            >
              <template v-if="thinking">
                <i class="el-icon-loading" style="margin-right: 6px"></i>
                <span>深度思考中...</span>
              </template>
              <template v-else>
                <svg-btn name="think"></svg-btn>
                <span>已深度思考（用时:{{ thinkDuration }}秒）</span>
                <i v-if="thinkVisible" class="el-icon el-icon-arrow-down"></i>
                <i v-else class="el-icon el-icon-arrow-down"></i>
              </template>
            </div>
            <div v-show="thinkVisible" class="sse-thinking-container">
              <sse-result-view :output="aiThinkingResult"></sse-result-view>
            </div>
          </template>

          <sse-result-view :output="aiResult"></sse-result-view>
        </div>
        <div class="action-buttons">
          <el-button type="primary" :disabled="loading" @click="saveQuestions"
            >保存试题</el-button
          >
          <el-button :disabled="loading" @click="clearPreview"
            >清空预览</el-button
          >
        </div>
      </div>
    </div>
  </el-dialog>
</template>

<script>
import { BASE_QUESTION_TYPES } from "@/constants/constants";
import { createParser } from "eventsource-parser";
import PropertyTreeSelect from "../PropertyTreeSelect.vue";
import SseResultView from "./SseResultView.vue";
import {
  sourceDetailPageListApi,
  aiBuildQuestionApi,
  aiBuildQuestionSaveApi,
} from "../../api";

import { courseOutlineParsedCheckApi } from "@/modules/questions/api";

import { fetchTime } from "@/plugins/syncServerTime";
import { getAuthorization } from "@/plugins/crypto";

export default {
  name: "AiQuestionCreateDialog",
  components: {
    PropertyTreeSelect,
    SseResultView,
  },
  props: {
    courseInfo: {
      type: Object,
      default: () => ({ id: "", name: "", code: "" }),
    },
  },
  data() {
    return {
      modalIsShow: false,
      formModel: this.getInitForm(),
      questionTypes: [],
      rules: {
        courseId: [
          {
            required: true,
            message: "请选择课程",
            trigger: "change",
          },
        ],
        questionCount: [
          {
            required: true,
            message: "请输入出题数量",
            trigger: "change",
          },
        ],
        optionCount: [
          {
            required: true,
            message: "请输入选项个数",
            trigger: "change",
          },
        ],
        questionType: [
          {
            required: true,
            message: "请选择题型",
            trigger: "change",
          },
        ],
      },
      courseOutlineParsed: false,
      // ai question result
      taskId: "",
      aiResult: "",
      aiThinkingResult: "",
      thinking: false,
      thinkVisible: true,
      thinkDuration: "",
      loading: false,
      controller: null,
      parser: null,
    };
  },
  computed: {
    isChoiceQuestion() {
      return ["SINGLE_ANSWER_QUESTION", "MULTIPLE_ANSWER_QUESTION"].includes(
        this.formModel.questionType
      );
    },
  },
  methods: {
    scrollToBottom() {
      const container = this.$refs.sseOuiputContainerRef;
      if (container) {
        container.scrollTop = container.scrollHeight;
      }
    },
    close() {
      this.modalIsShow = false;
    },
    open() {
      this.modalIsShow = true;
    },
    async checkCourseOutlineParsed() {
      if (!this.courseInfo.id || !this.courseInfo.outlineFilePath) return;
      const res = await courseOutlineParsedCheckApi(this.courseInfo.id).catch(
        () => {}
      );
      if (!res) return;
      this.courseOutlineParsed = res.data;
    },
    async getQuestionTypes() {
      if (!this.courseInfo.id) return;
      const res = await sourceDetailPageListApi({
        courseId: this.courseInfo.id,
        rootOrgId: this.$store.state.user.rootOrgId,
        pageSize: 100,
        pageNum: 1,
      }).catch(() => {});

      if (!res) return;

      const baseQuestionCodes = BASE_QUESTION_TYPES.map((item) => item.code);
      this.questionTypes = (res.data.content || []).filter((item) =>
        baseQuestionCodes.includes(item.questionType)
      );

      if (this.questionTypes.length > 0) {
        this.switchType(this.questionTypes[0]);
      }
    },
    switchType(item) {
      this.formModel.questionType = item.questionType;
      this.formModel.questionTypeName = item.name;
      this.$refs.form.validateField("questionType");
    },
    getInitForm() {
      return {
        questionType: "SINGLE_CHOICE",
        questionTypeName: "",
        questionCount: 1,
        optionCount: 4,
        syllabus: false,
        syllabusNotes: "",
        propertyIdList: [],
        knowledgeNotes: "",
      };
    },
    handleOpened() {
      this.formModel = this.getInitForm();
      this.getQuestionTypes();
      this.getInitForm();
      this.checkCourseOutlineParsed();
    },
    handleClose() {
      this.aiResult = "";
      this.aiThinkingResult = "";
      this.taskId = "";
      this.thinking = false;
      this.thinkDuration = "";
      this.courseOutlineParsed = false;
      this.stopStream();
    },
    setAuth(config) {
      const headers = {};
      let userSession = sessionStorage.getItem("user");
      if (userSession) {
        let user = JSON.parse(userSession);
        const timestamp = fetchTime();
        const authorization = getAuthorization(
          {
            method: config.method,
            uri: config.url.split("?")[0].trim(),
            timestamp,
            sessionId: user.sessionId,
            token: user.accessToken,
          },
          "token"
        );
        headers["Authorization"] = authorization;
        headers["time"] = timestamp;
      }
      return headers;
    },
    async toBuildQuestion() {
      const valid = await this.$refs.form.validate().catch(() => false);
      if (!valid) return;

      if (this.loading) return;

      this.stopStream(); // 清理前一个流
      this.aiResult = "";
      this.aiThinkingResult = "";
      this.thinkDuration = "";
      this.taskId = "";
      this.loading = true;

      // 设置60秒超时
      const timeoutId = setTimeout(() => {
        this.controller.abort();
        this.$message.error("请求超时！");
        this.loading = false;
      }, 60000);

      try {
        this.controller = new AbortController();
        const res = await aiBuildQuestionApi(
          {
            ...this.formModel,
            courseId: this.courseInfo.id,
            rootOrgId: this.$store.state.user.rootOrgId,
          },
          {
            headers: {
              "Content-Type": "application/json",
              Accept: "text/event-stream",
              "Cache-Control": "no-cache",
              Connection: "keep-alive",
              ...this.setAuth({
                method: "post",
                url: "/api/uq_basic/ai/question/stream/build",
              }),
            },
            signal: this.controller.signal, // 使用AbortController的signal
          }
        );

        // 请求成功后清除超时定时器
        clearTimeout(timeoutId);
        const startThinkingTime = Date.now();
        this.thinking = true;

        const onEvent = (event) => {
          if (event.data === "[DONE]") {
            // console.log(this.aiResult);
            return;
          }
          try {
            const parsed = JSON.parse(event.data);
            if (!this.taskId && parsed.taskId) {
              this.taskId = parsed.taskId;
              return;
            }

            if (
              parsed.choices &&
              parsed.choices[0] &&
              parsed.choices[0].delta
            ) {
              const { content, reasoning_content } = parsed.choices[0].delta;

              // 只要content不为null，则表示思考结束，开始处理生成结果内容
              if (content !== null) {
                this.thinking = false;

                if (!this.thinkDuration) {
                  this.thinkDuration = Math.round(
                    (Date.now() - startThinkingTime) / 1000
                  );
                }

                requestAnimationFrame(() => {
                  this.aiResult += content || "";
                  this.scrollToBottom();
                });
                return;
              }

              // 处理思考过程内容
              requestAnimationFrame(() => {
                this.aiThinkingResult += reasoning_content || "";
                this.scrollToBottom();
              });
            }
          } catch (e) {
            console.error(
              "Error parsing SSE JSON:",
              e,
              "Event data:",
              event.data
            );
          }
        };
        const onError = (error) => {
          this.thinking = false;
          console.error("Error parsing event:", error);
        };

        const parser = createParser({ onEvent, onError });
        this.parser = parser;

        // Pipe the response stream through TextDecoderStream and feed to parser
        const reader = res.body
          .pipeThrough(new TextDecoderStream())
          .getReader();
        // eslint-disable-next-line no-constant-condition
        while (true) {
          const { done, value } = await reader.read();
          if (done) {
            break;
          }
          this.parser.feed(value);
        }
      } catch (err) {
        console.error("流式处理错误：", err);
        this.thinking = false;
        // 请求出错时清除超时定时器
        clearTimeout(timeoutId);
      } finally {
        this.loading = false;
        this.controller = null; // Ensure controller is reset
      }
    },
    stopStream() {
      this.controller?.abort();
      this.controller = null;
      this.parser = null;
      this.loading = false;
    },
    async saveQuestions() {
      if (this.loading) return;
      this.loading = true;
      const res = await aiBuildQuestionSaveApi({
        aiResult: this.aiResult,
        taskId: this.taskId,
      }).catch(() => {});
      this.loading = false;
      if (!res) return;
      this.$message.success("保存成功");
      this.$emit("modified");
      this.close();
    },
    clearPreview() {
      this.aiResult = "";
      this.aiThinkingResult = "";
      this.taskId = "";
    },
  },
  beforeDestroy() {
    this.stopStream(); // 在组件销毁前清理流
  },
};
</script>

<style>
.thinking-container {
  background-color: #f8f9fa;
  border-left: 3px solid #409eff;
  margin-bottom: 20px;
}
</style>
