<template>
  <el-drawer
    v-model="visible"
    :title="isAdd ? '新增软件产品' : '编辑软件产品'"
    size="560px"
    destroy-on-close
    @closed="onClosed"
  >
    <el-form ref="formRef" :model="form" :rules="rules" label-width="110px" v-loading="loading">
      <el-form-item label="软件名称" prop="name">
        <el-input v-model="form.name" placeholder="如：桌面客户端" />
      </el-form-item>
      <el-form-item label="产品 code" prop="code">
        <el-input
          v-model="form.code"
          placeholder="客户端检查更新时传的 code，唯一"
          :disabled="!isAdd"
        />
      </el-form-item>
      <el-form-item label="最新版本号" prop="latestVersion">
        <el-input v-model="form.latestVersion" placeholder="如 1.2.0" />
      </el-form-item>

      <el-form-item label="安装包">
        <el-upload
          ref="uploadRef"
          class="pkg-upload"
          :limit="1"
          :file-list="displayFileList"
          :http-request="handlePackageUpload"
          :on-remove="onRemovePackage"
          @exceed="onExceedReplace"
          accept=".zip,.exe,.dmg,.msi,.msix,.apk,.deb,.rpm,.7z,.pkg,.tar,.gz"
        >
          <el-button type="primary" :loading="uploading">
            {{ form.fileId ? "重新上传安装包" : "上传安装包" }}
          </el-button>
        </el-upload>
        <div v-if="uploadXHRActive" class="upload-progress-wrap">
          <el-progress
            :percentage="uploadPercent"
            :indeterminate="uploadIndeterminate"
            :stroke-width="10"
            striped
            striped-flow
          />
          <div class="upload-progress-text">
            <template v-if="!uploadIndeterminate">
              <span>{{ uploadPercent }}%</span>
              <span class="upload-sep">·</span>
              <span>{{ uploadSpeedText }}</span>
              <template v-if="uploadSizeText">
                <span class="upload-sep">·</span>
                <span>{{ uploadSizeText }}</span>
              </template>
            </template>
            <template v-else>
              <span>上传中…</span>
              <template v-if="uploadSpeedText && uploadSpeedText !== '—'">
                <span class="upload-sep">·</span>
                <span>{{ uploadSpeedText }}</span>
              </template>
              <template v-if="uploadSizeText">
                <span class="upload-sep">·</span>
                <span>{{ uploadSizeText }}</span>
              </template>
            </template>
          </div>
        </div>
        <div v-if="form.fileId" class="pkg-meta">
          <span>文件 ID：<code>{{ form.fileId }}</code></span>
        </div>
      </el-form-item>

      <el-form-item label="下载/更新地址">
        <el-input
          v-model="form.downloadUrl"
          type="textarea"
          :rows="2"
          placeholder="上传后自动填写；可改为 CDN 等完整 URL"
        />
      </el-form-item>

      <el-form-item label="强制更新">
        <el-switch v-model="form.forceUpdate" :active-value="1" :inactive-value="0" />
      </el-form-item>
      <el-form-item label="更新说明">
        <el-input v-model="form.releaseNotes" type="textarea" :rows="4" />
      </el-form-item>
      <el-form-item label="状态">
        <el-radio-group v-model="form.status">
          <el-radio-button :value="1">启用</el-radio-button>
          <el-radio-button :value="0">停用</el-radio-button>
        </el-radio-group>
      </el-form-item>
      <el-form-item label="排序">
        <el-input-number v-model="form.sort" :min="0" style="width: 100%" />
      </el-form-item>
      <el-form-item v-if="!isAdd && resolvedUrl" label="当前解析地址">
        <el-link :href="resolvedUrl" type="primary" target="_blank">{{ resolvedUrl }}</el-link>
      </el-form-item>
    </el-form>
    <template #footer>
      <el-button @click="visible = false">取消</el-button>
      <el-button type="primary" :loading="saving" @click="submit">保存</el-button>
    </template>
  </el-drawer>
</template>

<script setup>
import { ref, reactive, nextTick } from "vue";
import { ElMessage } from "element-plus";
import {
  getSoftwareUpgradeDetail,
  createSoftwareUpgrade,
  updateSoftwareUpgrade,
} from "@/api/softwareUpgrade";
import { getUserCate, createFileCate, getFileById } from "@/api/file";
import { smartUpload } from "@/utils/qiniuUpload";

const emit = defineEmits(["saved"]);

const visible = ref(false);
const loading = ref(false);
const saving = ref(false);
const uploading = ref(false);
const uploadXHRActive = ref(false);
const uploadPercent = ref(0);
const uploadIndeterminate = ref(false);
const uploadSpeedText = ref("—");
const uploadSizeText = ref("");
const isAdd = ref(false);
const resolvedUrl = ref("");
const formRef = ref(null);
const uploadRef = ref(null);
const displayFileList = ref([]);
const uploadedLabel = ref("");
const appsUpgradeCateId = ref(null);

const form = reactive({
  id: 0,
  name: "",
  code: "",
  latestVersion: "0.0.1",
  fileId: null,
  downloadUrl: "",
  forceUpdate: 0,
  releaseNotes: "",
  status: 1,
  sort: 0,
});

const rules = {
  name: [{ required: true, message: "请输入名称", trigger: "blur" }],
  code: [{ required: true, message: "请输入产品标识", trigger: "blur" }],
  latestVersion: [{ required: true, message: "请输入版本号", trigger: "blur" }],
};

function formatBytes(n) {
  if (n == null || !Number.isFinite(n) || n < 0) return "";
  if (n < 1024) return `${Math.round(n)} B`;
  if (n < 1024 * 1024) return `${(n / 1024).toFixed(n < 10240 ? 2 : 1)} KB`;
  if (n < 1024 * 1024 * 1024) return `${(n / (1024 * 1024)).toFixed(2)} MB`;
  return `${(n / (1024 * 1024 * 1024)).toFixed(2)} GB`;
}

/** @param {number} bps bytes per second */
function formatSpeed(bps) {
  if (bps == null || !Number.isFinite(bps) || bps <= 0) return "—";
  return `${formatBytes(bps)}/s`;
}

function absoluteFromSrc(src) {
  if (!src) return "";
  const s = String(src).trim();
  if (/^https?:\/\//i.test(s)) return s;
  const base = (import.meta.env.VITE_API_BASE_URL || "").replace(/\/$/, "");
  const path = s.startsWith("/") ? s : `/${s}`;
  return base ? `${base}${path}` : path;
}

async function ensureAppsUpgradeCate() {
  if (appsUpgradeCateId.value != null) {
    return appsUpgradeCateId.value;
  }
  const res = await getUserCate();
  if (res?.code !== 200 || !Array.isArray(res.data)) {
    return null;
  }
  const found = res.data.find(
    (c) => String(c.name || "").trim().toLowerCase() === "appsupgrade"
  );
  if (found && found.id) {
    appsUpgradeCateId.value = Number(found.id);
    return appsUpgradeCateId.value;
  }
  const cr = await createFileCate({ name: "appsupgrade" });
  if (cr?.code === 200 && cr.data?.id != null) {
    appsUpgradeCateId.value = Number(cr.data.id);
    return appsUpgradeCateId.value;
  }
  ElMessage.error(cr?.msg || "创建文件分组 appsupgrade 失败");
  return null;
}

function reset() {
  form.id = 0;
  form.name = "";
  form.code = "";
  form.latestVersion = "0.0.1";
  form.fileId = null;
  form.downloadUrl = "";
  form.forceUpdate = 0;
  form.releaseNotes = "";
  form.status = 1;
  form.sort = 0;
  resolvedUrl.value = "";
  displayFileList.value = [];
  uploadedLabel.value = "";
  uploadXHRActive.value = false;
  uploadPercent.value = 0;
  uploadIndeterminate.value = false;
  uploadSpeedText.value = "—";
  uploadSizeText.value = "";
  uploadRef.value?.clearFiles?.();
}

function onClosed() {
  reset();
}

function onRemovePackage() {
  form.fileId = null;
  form.downloadUrl = "";
  uploadedLabel.value = "";
  displayFileList.value = [];
}

/** Element Plus：超出 limit 时传入待加入的文件列表（一般为 File[]） */
function onExceedReplace(files) {
  const first = files[0];
  const raw = first?.raw != null ? first.raw : first;
  uploadRef.value?.clearFiles?.();
  form.fileId = null;
  form.downloadUrl = "";
  uploadedLabel.value = "";
  displayFileList.value = [];
  if (raw) {
    handlePackageUpload({ file: raw, onSuccess: () => {}, onError: () => {} });
  }
}

async function handlePackageUpload(options) {
  const file = options.file?.raw != null ? options.file.raw : options.file;
  if (!file) {
    options.onError?.(new Error("无文件"));
    return;
  }
  uploading.value = true;
  try {
    const cateId = await ensureAppsUpgradeCate();
    if (!cateId) {
      options.onError?.(new Error("no category"));
      return;
    }
    
    uploadXHRActive.value = true;
    uploadPercent.value = 0;
    uploadIndeterminate.value = false;
    uploadSpeedText.value = "—";
    uploadSizeText.value = "";
    const xhrStart = Date.now();
    let lastLoaded = 0;
    let lastTick = xhrStart;
    let emaBps = 0;
    
    // 使用智能上传（自动选择本地或七牛云）
    const result = await smartUpload(file, {
      cate: cateId,
      onProgress: (progress) => {
        const now = Date.now();
        const loaded = progress.loaded;
        const total = progress.total || 0;
        const elapsedSec = (now - xhrStart) / 1000;
        const dt = (now - lastTick) / 1000;
        
        if (dt >= 0.07 && loaded >= lastLoaded) {
          const inst = (loaded - lastLoaded) / dt;
          emaBps = emaBps > 0 ? emaBps * 0.72 + inst * 0.28 : inst;
          lastLoaded = loaded;
          lastTick = now;
        }
        
        const avgBps = elapsedSec > 0.12 ? loaded / elapsedSec : 0;
        const showBps = emaBps > 0 ? emaBps : avgBps;
        uploadSpeedText.value = showBps > 0 ? formatSpeed(showBps) : elapsedSec > 0.05 ? formatSpeed(avgBps) : "—";

        if (total > 0) {
          uploadIndeterminate.value = false;
          uploadPercent.value = Math.min(100, Math.round((loaded * 100) / total));
          uploadSizeText.value = `${formatBytes(loaded)} / ${formatBytes(total)}`;
        } else {
          uploadIndeterminate.value = true;
          uploadSizeText.value = loaded > 0 ? `已上传 ${formatBytes(loaded)}` : "";
        }
      },
    });
    
    // 上传成功
    form.fileId = result.id;
    form.downloadUrl = result.url;
    uploadedLabel.value = result.name || file.name || "安装包";
    displayFileList.value = [{ name: uploadedLabel.value, uid: `pkg-${form.fileId}-${Date.now()}` }];
    ElMessage.success("上传成功");
    options.onSuccess?.(result);
  } catch (e) {
    ElMessage.error(e?.message || "上传失败");
    options.onError?.(e);
  } finally {
    uploading.value = false;
    uploadXHRActive.value = false;
    uploadPercent.value = 0;
    uploadIndeterminate.value = false;
    uploadSpeedText.value = "—";
    uploadSizeText.value = "";
  }
}

async function open(id) {
  reset();
  isAdd.value = !id;
  visible.value = true;
  appsUpgradeCateId.value = null;
  await nextTick();
  formRef.value?.clearValidate?.();
  if (!id) return;
  loading.value = true;
  try {
    const res = await getSoftwareUpgradeDetail(id);
    if (res?.code !== 200 || !res.data) {
      ElMessage.error(res?.msg || "加载失败");
      visible.value = false;
      return;
    }
    const d = res.data;
    form.id = d.id;
    form.name = d.name || "";
    form.code = d.code || "";
    form.latestVersion = d.latestVersion || "0.0.1";
    form.fileId = d.fileId != null ? Number(d.fileId) : null;
    form.downloadUrl = d.downloadUrl || d.resolvedDownloadUrl || "";
    form.forceUpdate = d.forceUpdate ? 1 : 0;
    form.releaseNotes = d.releaseNotes || "";
    form.status = d.status !== 0 ? 1 : 0;
    form.sort = d.sort ?? 0;
    resolvedUrl.value = d.resolvedDownloadUrl || "";

    if (form.fileId) {
      try {
        const fr = await getFileById(form.fileId);
        if (fr?.code === 200 && fr.data) {
          uploadedLabel.value = fr.data.name || `文件 #${form.fileId}`;
        } else {
          uploadedLabel.value = `文件 #${form.fileId}`;
        }
      } catch {
        uploadedLabel.value = `文件 #${form.fileId}`;
      }
      displayFileList.value = [
        { name: uploadedLabel.value, uid: `exist-${form.fileId}` },
      ];
    }
  } finally {
    loading.value = false;
  }
}

async function submit() {
  try {
    await formRef.value?.validate();
  } catch {
    return;
  }
  const payload = {
    name: form.name.trim(),
    code: form.code.trim(),
    latestVersion: form.latestVersion.trim(),
    downloadUrl: form.downloadUrl.trim() || undefined,
    forceUpdate: form.forceUpdate,
    releaseNotes: form.releaseNotes.trim() || undefined,
    status: form.status,
    sort: form.sort,
  };
  if (form.fileId != null && form.fileId !== "" && Number(form.fileId) > 0) {
    payload.fileId = Number(form.fileId);
  } else {
    payload.fileId = 0;
  }

  saving.value = true;
  try {
    let res;
    if (isAdd.value) {
      res = await createSoftwareUpgrade(payload);
    } else {
      res = await updateSoftwareUpgrade(form.id, payload);
    }
    if (res?.code === 200) {
      ElMessage.success("已保存");
      visible.value = false;
      emit("saved");
    } else {
      ElMessage.error(res?.msg || "失败");
    }
  } finally {
    saving.value = false;
  }
}

defineExpose({ open });
</script>

<style scoped>
.hint {
  margin: 0 0 10px;
  font-size: 12px;
  color: var(--el-text-color-secondary);
  line-height: 1.55;
}
.hint code {
  padding: 0 4px;
  background: var(--el-fill-color-light);
  border-radius: 4px;
}
.pkg-upload {
  width: 100%;
}
.upload-progress-wrap {
  margin-top: 10px;
  width: 100%;
}
.upload-progress-text {
  display: block;
  margin-top: 6px;
  font-size: 12px;
  color: var(--el-text-color-secondary);
  line-height: 1.5;
  word-break: break-all;
}
.upload-progress-text .upload-sep {
  margin: 0 0.35em;
  opacity: 0.55;
}
.pkg-meta {
  margin-top: 8px;
  font-size: 12px;
  color: var(--el-text-color-secondary);
}
.pkg-meta code {
  font-size: 12px;
}
</style>
