<template>
  <div class="flex flex-col bg-base-100 justify-center items-center gap-4">
    <!-- Title -->
    <h1 class="font-bold text-2xl">比特流文件</h1>

    <!-- 示例比特流下载区域 (仅在有examId时显示) -->
    <div v-if="examId && availableBitstreams.length > 0" class="w-full">
      <fieldset class="fieldset w-full">
        <legend class="fieldset-legend text-sm">示例比特流文件</legend>
        <div class="space-y-2">
          <div
            v-for="bitstream in availableBitstreams"
            :key="bitstream.id"
            class="flex items-center justify-between p-2 border-2 border-base-300 rounded-lg"
          >
            <span class="text-sm">{{ bitstream.name }}</span>
            <div class="flex gap-2">
              <button
                @click="handleExampleBitstream('download', bitstream)"
                class="btn btn-sm btn-secondary"
                :disabled="currentTask !== 'none'"
              >
                <div
                  v-if="
                    currentTask === 'downloading' &&
                    currentBitstreamId === bitstream.id
                  "
                >
                  <span class="loading loading-spinner loading-xs"></span>
                  下载中...
                </div>
                <div v-else>下载示例</div>
              </button>
              <button
                @click="handleExampleBitstream('program', bitstream)"
                class="btn btn-sm btn-primary"
                :disabled="currentTask !== 'none'"
              >
                <div
                  v-if="
                    currentTask === 'programming' &&
                    currentBitstreamId === bitstream.id
                  "
                >
                  <span class="loading loading-spinner loading-xs"></span>
                  烧录中...
                </div>
                <div v-else>直接烧录</div>
              </button>
            </div>
          </div>
        </div>
      </fieldset>
    </div>

    <!-- 分割线 -->
    <div v-if="examId && availableBitstreams.length > 0" class="divider">
      或
    </div>

    <!-- Input File -->
    <fieldset class="fieldset w-full">
      <legend class="fieldset-legend text-sm">上传自定义比特流文件</legend>
      <input
        type="file"
        ref="fileInput"
        class="file-input w-full"
        @change="handleFileChange"
      />
      <label class="fieldset-label">文件最大容量: {{ maxMemory }}MB</label>
    </fieldset>

    <!-- Upload Button -->
    <div class="card-actions w-full">
      <button
        @click="handleUploadAndDownload"
        class="btn btn-primary grow"
        :disabled="currentTask !== 'none'"
      >
        <div v-if="currentTask === 'uploading'">
          <span class="loading loading-spinner"></span>
          上传中...
        </div>
        <div v-else-if="currentTask === 'programming'">
          <span class="loading loading-spinner"></span>
          {{ currentProgressPercent }}% ...
        </div>
        <div v-else>上传并下载</div>
      </button>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { ref, useTemplateRef, onMounted } from "vue";
import { AuthManager } from "@/utils/AuthManager";
import { useDialogStore } from "@/stores/dialog";
import { useEquipments } from "@/stores/equipments";
import { useRequiredInjection } from "@/utils/Common";
import { useAlertStore } from "./Alert";
import { ResourceClient, ResourcePurpose } from "@/APIClient";
import { useProgressStore } from "@/stores/progress";
import { ProgressStatus, type ProgressInfo } from "@/utils/signalR/server.Hubs";

interface Props {
  maxMemory?: number;
  examId?: string;
}

const props = withDefaults(defineProps<Props>(), {
  maxMemory: 4,
  examId: "",
});

const emits = defineEmits<{
  finishedUpload: [file: File];
}>();

const alert = useRequiredInjection(useAlertStore);
const progressTracker = useProgressStore();
const dialog = useDialogStore();
const eqps = useEquipments();

const availableBitstreams = ref<{ id: string; name: string }[]>([]);
const fileInput = useTemplateRef("fileInput");
const bitstream = ref<File | undefined>(undefined);

// 用一个状态变量替代多个
const currentTask = ref<"none" | "uploading" | "downloading" | "programming">(
  "none",
);
const currentBitstreamId = ref<string>("");
const currentProgressId = ref<string>("");
const currentProgressPercent = ref<number>(0);

onMounted(async () => {
  if (bitstream.value && fileInput.value) {
    let fileList = new DataTransfer();
    fileList.items.add(bitstream.value);
    fileInput.value.files = fileList.files;
  }
  await loadAvailableBitstreams();
});

function handleFileChange(event: Event): void {
  const target = event.target as HTMLInputElement;
  const file = target.files?.[0];
  bitstream.value = file || undefined;
}

function checkFileInput(): boolean {
  if (!bitstream.value) {
    dialog.error(`未选择文件`);
    return false;
  }
  const maxBytes = props.maxMemory! * 1024 * 1024;
  if (bitstream.value.size > maxBytes) {
    dialog.error(`文件大小超过最大限制: ${props.maxMemory}MB`);
    return false;
  }
  return true;
}

async function downloadBitstream() {
  currentTask.value = "programming";
  try {
    currentProgressId.value = await eqps.jtagDownloadBitstream(
      currentBitstreamId.value,
    );
    progressTracker.register(
      currentProgressId.value,
      "programBitstream",
      handleProgressUpdate,
    );
  } catch {
    dialog.error("比特流烧录失败");
    cleanProgressTracker();
  }
}

function cleanProgressTracker() {
  currentTask.value = "none";
  currentProgressId.value = "";
  currentBitstreamId.value = "";
  currentProgressPercent.value = 0;
  progressTracker.unregister(currentProgressId.value, "programBitstream");
}

async function loadAvailableBitstreams() {
  if (!props.examId) {
    availableBitstreams.value = [];
    return;
  }
  try {
    const resourceClient = AuthManager.createClient(ResourceClient);
    const resources = await resourceClient.getResourceList(
      props.examId,
      "bitstream",
      ResourcePurpose.Template,
    );
    availableBitstreams.value =
      resources.map((r) => ({ id: r.id, name: r.name })) || [];
  } catch (error) {
    availableBitstreams.value = [];
  }
}

// 统一处理示例比特流的下载/烧录
async function handleExampleBitstream(
  action: "download" | "program",
  bitstreamObj: { id: string; name: string },
) {
  if (currentTask.value !== "none") return;
  currentBitstreamId.value = bitstreamObj.id;
  if (action === "download") {
    currentTask.value = "downloading";
    try {
      const resourceClient = AuthManager.createClient(ResourceClient);
      const response = await resourceClient.getResourceById(bitstreamObj.id);
      if (response && response.data) {
        const url = URL.createObjectURL(response.data);
        const link = document.createElement("a");
        link.href = url;
        link.download = response.fileName || bitstreamObj.name;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        URL.revokeObjectURL(url);
        alert.info("示例比特流下载成功");
      } else {
        alert.error("下载失败：响应数据为空");
      }
    } catch {
      alert.error("下载示例比特流失败");
    } finally {
      currentTask.value = "none";
      currentBitstreamId.value = "";
    }
  } else if (action === "program") {
    currentBitstreamId.value = bitstreamObj.id;
    await downloadBitstream();
  }
}

// 上传并下载
async function handleUploadAndDownload() {
  if (currentTask.value !== "none") return;
  if (!checkFileInput()) return;

  currentTask.value = "uploading";
  let uploadedBitstreamId: string | null = null;
  try {
    uploadedBitstreamId = await eqps.jtagUploadBitstream(
      bitstream.value!,
      props.examId || "",
    );
    if (!uploadedBitstreamId) throw new Error("上传失败");
    emits("finishedUpload", bitstream.value!);
  } catch {
    dialog.error("上传失败");
    currentTask.value = "none";
    return;
  }

  currentBitstreamId.value = uploadedBitstreamId;

  await downloadBitstream();
}

function handleProgressUpdate(msg: ProgressInfo) {
  // console.log(msg);
  if (msg.status === ProgressStatus.Running)
    currentProgressPercent.value = msg.progressPercent;
  else if (msg.status === ProgressStatus.Failed) {
    dialog.error(`比特流烧录失败: ${msg.errorMessage}`);
    cleanProgressTracker();
  } else if (msg.status === ProgressStatus.Completed) {
    dialog.info("比特流烧录成功");
    cleanProgressTracker();
  }
}
</script>

<style scoped lang="postcss">
@import "../assets/main.css";
</style>
