<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
    @opened="handleOpened"
    @close="handleClose"
  >
    <div slot="title" class="dialog-title-container">
      <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>

    <div class="dialog-content-container">
      <div class="left-panel">
        <el-form
          ref="form"
          :model="formModel"
          :rules="rules"
          label-width="90px"
          class="form-container"
        >
          <el-form-item prop="questionType" label="选择题型">
            <el-button
              v-for="item in questionTypes"
              :key="item.id"
              :type="
                formModel.questionType === item.questionType
                  ? 'primary'
                  : 'default'
              "
              size="small"
              @click="switchType(item)"
              >{{ item.questionTypeName }}</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"
            ></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 label="教学大纲">
            <div class="box-justify">
              <el-checkbox v-model="formModel.syllabus"
                >教学大纲pdf</el-checkbox
              >
              <upload-button
                btn-content="上传文件"
                btn-icon="icon icon-import"
                :disabled="uploading || !courseInfo.id"
                :upload-data="{ id: courseInfo.id }"
                :upload-url="uploadUrl"
                :format="importFileTypes"
                @valid-error="validError"
                @upload-success="uploadSuccess"
              ></upload-button>
            </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"
              :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" @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">
          <pre>{{ output }}</pre>
        </div>
        <div class="action-buttons">
          <el-button type="primary" @click="saveQuestions">保存试题</el-button>
          <el-button @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 "../components/PropertyTreeSelect.vue";
import UploadButton from "@/components/UploadButton.vue";
import { QUESTION_API } from "@/constants/constants";
import {
  sourceDetailPageListApi,
  aiBuildQuestionApi,
  aiBuildQuestionSaveApi,
} from "../api";

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

export default {
  name: "AiQuestionCreateDialog",
  components: {
    PropertyTreeSelect,
    UploadButton,
  },
  props: {
    courseInfo: {
      type: Object,
      default: () => ({ id: "", name: "", code: "" }),
    },
  },
  data() {
    return {
      modalIsShow: false,
      formModel: this.getInitForm(),
      questionTypes: [],
      sseData: "", // 用于存储SSE流式数据
      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",
          },
        ],
      },
      // upload
      uploading: false,
      importFileTypes: ["pdf"],
      uploadUrl: `${QUESTION_API}/course/outline/upload`,
      showIframeDialog: false,
      // ai question result
      taskId: "",
      aiResult: "",
      // output
      output: "",
      loading: false,
      controller: null,
      parser: null,
    };
  },
  computed: {
    isChoiceQuestion() {
      return ["SINGLE_ANSWER_QUESTION", "MULTIPLE_ANSWER_QUESTION"].includes(
        this.formModel.questionType
      );
    },
  },
  watch: {
    cancel() {
      this.modalIsShow = false;
    },
    open() {
      this.modalIsShow = true;
    },
  },
  methods: {
    close() {
      this.modalIsShow = false;
    },
    open() {
      this.modalIsShow = true;
    },
    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.formModel.questionType = this.questionTypes[0].questionType;
      }
    },
    switchType(item) {
      this.formModel.questionType = item.questionType;
      this.$refs.form.validateField("questionType");
    },
    getInitForm() {
      return {
        questionType: "SINGLE_CHOICE",
        questionCount: 1,
        optionCount: 4,
        syllabus: false,
        syllabusNotes: "",
        propertyIdList: [],
        knowledgeNotes: "",
      };
    },
    handleOpened() {
      this.formModel = this.getInitForm();
      this.getQuestionTypes();
      this.getInitForm();
    },
    handleClose() {
      this.stopStream();
    },
    validError(error) {
      this.$message.error(error.message);
    },
    uploadSuccess(response) {
      console.log(response);
      // TODO:
      this.$message.success("上传成功！");
    },
    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.output = "";
      this.aiResult = ""; // Reset aiResult for the new stream
      this.taskId = ""; // Reset taskId for the new stream
      this.loading = true;

      try {
        const res = await aiBuildQuestionApi(
          {
            ...this.formModel,
            courseId: this.courseInfo.id,
            rootOrgId: this.$store.state.user.rootOrgId,
          },
          {
            headers: {
              "Content-Type": "application/json",
              ...this.setAuth({
                method: "post",
                url: "/api/uq_basic/ai/question/stream/build",
              }),
            },
            signal: (this.controller = new AbortController()).signal, // Ensures a new controller for each call
          }
        );

        const onEvent = (event) => {
          console.log(event);
          console.log(Date.now());
          if (event.data === "[DONE]") {
            this.controller.abort(); // End the stream
            return;
          }
          try {
            const parsed = JSON.parse(event.data);
            if (!this.taskId && parsed.id) {
              this.taskId = parsed.id;
            }
            if (
              parsed.choices &&
              parsed.choices[0] &&
              parsed.choices[0].delta
            ) {
              const content = parsed.choices[0].delta.content;
              console.log(content);
              if (typeof content === "string") {
                requestAnimationFrame(() => {
                  this.output += content;
                  this.aiResult += content;
                });
              }
            }
          } catch (e) {
            console.error(
              "Error parsing SSE JSON:",
              e,
              "Event data:",
              event.data
            );
          }
        };
        const onError = (error) => {
          console.error("Error parsing event:", error);
          if (error.type === "invalid-field") {
            console.error("Field name:", error.field);
            console.error("Field value:", error.value);
            console.error("Line:", error.line);
          } else if (error.type === "invalid-retry") {
            console.error("Invalid retry interval:", error.value);
          }
        };

        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) {
        if (err.name !== "AbortError") {
          console.error("流式处理错误：", err);
        }
      } 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.output = "";
    },
  },
  beforeDestroy() {
    this.stopStream(); // 在组件销毁前清理流
  },
};
</script>
