<template>
  <view class="aigc-detail-page">
    <AigcTopBar :points="pointBalance" @back="handleBack" @history="handleOpenRecords" @recharge="handleRecharge" />

    <view class="aigc-detail-content">
      <template v-if="taskDetail">
        <ResultPreview v-if="result.cover" class="aigc-detail-preview" :result="result" />
        <view class="aigc-detail-controls">
          <!-- <ResultMeta :items="metaItems" /> -->
          <ContinuationCard v-if="result.mediaType === 'image'" :info="continuationInfo"
            @upgrade="handleUpgradeToVideo" />
          <ResultActions :saving="isSaving" :media-type="result.mediaType" :share-ready="Boolean(shareKey)"
            :share-preparing="isPreparingShare" @save="handleSave" @prepare-share="handlePrepareShare" />

          <view class="aigc-detail-text-actions">
            <view class="aigc-detail-text-action" @tap="handleRegenerate">再生成一版</view>
            <view class="aigc-detail-text-action" @tap="handleChangeTemplate">换个模板</view>
            <view class="aigc-detail-text-action" @tap="handleOpenRecords">历史记录</view>
          </view>
        </view>
      </template>
    </view>

    <Privacy :visible="privacyVisible" :contract-name="privacyContractName" @agree="handlePrivacyAgree"
      @disagree="handlePrivacyDisagree" />
    <RegenerateConfirmPopup ref="regeneratePopupRef" :cost="regenerateCost" :balance="pointBalance"
      :loading="isRegenerating" @confirm="handleConfirmRegenerate" />
    <PointInsufficientDialog v-if="pointDialogVisible" :cost="regenerateCost" :balance="pointBalance"
      @cancel="handleClosePointDialog" @recharge="handlePointRecharge" />
  </view>
</template>

<script setup>
import { computed, ref } from "vue";
import { onLoad, onShareAppMessage, onShow } from "@dcloudio/uni-app";
import Privacy from "@/components/Privacy/index.vue";
import AigcTopBar from "@/pages-aigc/components/AigcTopBar/index.vue";
import { useCurrentCredit } from "@/pages-aigc/hooks/useCurrentCredit.js";
import { getWechatLoginCode } from "@/pages-aigc/services/wechatLogin.js";
import {
  createAigcGeneratorTask,
  createAigcGeneratorTaskShare,
  getAigcGeneratorTaskDetail,
} from "@/pages-aigc/request/AigcApi.js";
import PointInsufficientDialog from "@/pages-aigc/useTemplate/components/PointInsufficientDialog/index.vue";
import ContinuationCard from "./components/ContinuationCard/index.vue";
import RegenerateConfirmPopup from "./components/RegenerateConfirmPopup/index.vue";
import ResultActions from "./components/ResultActions/index.vue";
import ResultPreview from "./components/ResultPreview/index.vue";

const { pointBalance, fetchCurrentCredit } = useCurrentCredit();
const taskId = ref("");
const taskDetail = ref(null);
const isSaving = ref(false);
const isPreparingShare = ref(false);
const shareKey = ref("");
const privacyVisible = ref(false);
const privacyContractName = ref("隐私保护指引");
const pendingSaveAfterPrivacy = ref(false);
const regeneratePopupRef = ref(null);
const isRegenerating = ref(false);
const isUpgradingToVideo = ref(false);
const pointDialogVisible = ref(false);

const GENERATOR_TYPE_TEXT = {
  0: "图片版",
  1: "视频版",
  2: "升视频",
};

const TASK_STATUS_TEXT = {
  0: "排队中",
  1: "生成中",
  2: "已完成",
  3: "生成失败",
  4: "视频生成中",
};

const getMappedText = (mapping, value, prefix) => {
  if (Object.prototype.hasOwnProperty.call(mapping, value)) {
    return mapping[value];
  }
  return value === undefined || value === null || value === "" ? "-" : `${prefix}${value}`;
};

const formatDateOnly = (value) => {
  if (!value) return "-";
  return String(value).match(/^\d{4}-\d{2}-\d{2}/)?.[0] || "-";
};

const result = computed(() => {
  const record = taskDetail.value || {};

  const imageUrl = record.imageResultUrl || "";
  const videoUrl = record.videoResultUrl || "";
  const isVideo = [1, 2].includes(Number(record.generatorType));
  const typeText = getMappedText(GENERATOR_TYPE_TEXT, record.generatorType, "类型");
  const statusText = getMappedText(TASK_STATUS_TEXT, record.taskStatus, "状态");
  const consumedText =
    record.generatorCost === undefined || record.generatorCost === null || record.generatorCost === ""
      ? "-"
      : `${record.generatorCost}积分`;

  return {
    id: record.taskId,
    title: record.itemTitle || record.taskId || "生成结果",
    cover: isVideo ? videoUrl : imageUrl,
    imageResultUrl: imageUrl,
    videoResultUrl: videoUrl,
    mediaType: isVideo ? "video" : "image",
    accent: "#0a4d46",
    variantLabel: typeText,
    resultLabel: statusText,
    consumedText,
    desc: record.itemSubTitle || statusText,
  };
});

const metaItems = computed(() => {
  const record = taskDetail.value;
  if (!record) return [];

  const completeTime = formatDateOnly(
    record.videoGeneratorCompleteTime || record.imageGeneratorCompleteTime || record.createTime
  );

  return [
    {
      label: "状态",
      value: result.value.resultLabel,
    },
    {
      label: "已消耗",
      value: result.value.consumedText,
    },
    {
      label: "完成时间",
      value: completeTime,
    },
  ];
});

const sharePreviewImage = computed(() => taskDetail.value?.imageResultUrl || "");
const regenerateCost = computed(() => Math.max(0, Number(taskDetail.value?.generatorCost) || 0));
const continuationInfo = {
  title: "创意续作",
  desc: "让这张图动起来 · 5秒内动效视频",
  cost: "追加消耗 650积分",
  buttonText: "升级为动效视频",
};

const showPlaceholderToast = (title) => {
  uni.showToast({
    title,
    icon: "none",
  });
};

const fetchTaskDetail = async () => {
  uni.showLoading({
    title: "加载中",
    mask: true,
  });

  try {
    const res = await getAigcGeneratorTaskDetail({ taskId: taskId.value });
    if (res?.code === 0 && res.data && typeof res.data === "object" && !Array.isArray(res.data)) {
      taskDetail.value = res.data;
      prepareShareKey();
      return;
    }

    taskDetail.value = null;
    showPlaceholderToast("获取任务详情失败");
  } catch (error) {
    console.error("获取AIGC生成任务详情失败", error);
    taskDetail.value = null;
    showPlaceholderToast("获取任务详情失败");
  } finally {
    uni.hideLoading();
  }
};

onLoad((query = {}) => {
  taskId.value = String(query.taskId || "").trim();
  if (!taskId.value) {
    showPlaceholderToast("缺少任务ID");
    return;
  }

  fetchTaskDetail();
});

onShow(() => {
  isUpgradingToVideo.value = false;
  fetchCurrentCredit();
});

onShareAppMessage(() => {
  const shareInfo = {
    title: taskDetail.value?.itemTitle || "分享旅行作品",
    path: shareKey.value
      ? `/pages-aigc/sharedWork/sharedWork?shareKey=${encodeURIComponent(shareKey.value)}`
      : "/pages/index/index",
  };
  const imageUrl = sharePreviewImage.value;

  if (imageUrl) {
    shareInfo.imageUrl = imageUrl;
  }

  return shareInfo;
});

const prepareShareKey = async (showFeedback = false) => {
  if (isPreparingShare.value || !taskId.value) return;
  if (shareKey.value) return;

  isPreparingShare.value = true;

  try {
    const res = await createAigcGeneratorTaskShare({ taskId: taskId.value });
    const nextShareKey = String(res?.data?.shareKey || "").trim();
    if (res?.code === 0 && nextShareKey) {
      shareKey.value = nextShareKey;
      if (showFeedback) {
        showPlaceholderToast("分享已准备，请再次点击");
      }
      return;
    }

    if (showFeedback) {
      showPlaceholderToast(res?.msg || "创建分享失败");
    }
  } catch (error) {
    console.error("创建AIGC任务分享失败", error);
    if (showFeedback) {
      showPlaceholderToast("创建分享失败");
    }
  } finally {
    isPreparingShare.value = false;
  }
};

const handlePrepareShare = () => {
  prepareShareKey(true);
};

const handleBack = () => {
  const pages = getCurrentPages();
  if (pages.length > 1) {
    uni.navigateBack();
  }
};

const handleRecharge = () => {
  uni.navigateTo({
    url: "/pages-aigc/recharge/recharge",
    fail: () => showPlaceholderToast("打开充值页面失败"),
  });
};

const handleUpgradeToVideo = () => {
  if (isUpgradingToVideo.value || result.value.mediaType !== "image") return;

  const sourceTaskId = String(taskDetail.value?.taskId || taskId.value || "").trim();
  if (!sourceTaskId) {
    showPlaceholderToast("缺少任务ID");
    return;
  }

  const templateId = String(taskDetail.value?.templateId || "").trim();
  const templateItemId = String(taskDetail.value?.templateItemId || "").trim();
  const query = [
    templateId && `templateId=${encodeURIComponent(templateId)}`,
    `upgradeTaskId=${encodeURIComponent(sourceTaskId)}`,
    templateItemId && `upgradeTemplateItemId=${encodeURIComponent(templateItemId)}`,
  ]
    .filter(Boolean)
    .join("&");

  isUpgradingToVideo.value = true;
  uni.navigateTo({
    url: `/pages-aigc/useTemplate/useTemplate?${query}`,
    fail: () => {
      isUpgradingToVideo.value = false;
      showPlaceholderToast("打开图片生成页面失败");
    },
  });
};

const getMediaFileExtension = (url, mediaType) => {
  const pathname = String(url || "").split(/[?#]/)[0];
  const matchedExtension = pathname.match(/\.([a-z0-9]{2,5})$/i)?.[1]?.toLowerCase();
  const supportedExtensions =
    mediaType === "video" ? ["mp4", "mov", "m4v", "3gp"] : ["jpg", "jpeg", "png", "webp", "gif"];

  if (matchedExtension && supportedExtensions.includes(matchedExtension)) {
    return `.${matchedExtension}`;
  }
  return mediaType === "video" ? ".mp4" : ".jpg";
};

const createMediaError = (stage, error = {}) => ({
  stage,
  errMsg: String(error?.errMsg || error?.message || ""),
  statusCode: error?.statusCode,
});

const downloadMedia = (url, mediaType) =>
  new Promise((resolve, reject) => {
    if (!/^https?:\/\//i.test(url)) {
      resolve({ filePath: url, shouldCleanup: false });
      return;
    }

    const downloadOptions = {
      url,
      success: (res) => {
        const filePath = res.filePath || res.tempFilePath;
        if (res.statusCode === 200 && filePath) {
          resolve({ filePath, shouldCleanup: Boolean(downloadOptions.filePath) });
          return;
        }
        reject(createMediaError("download", res));
      },
      fail: (error) => reject(createMediaError("download", error)),
    };

    // 微信端显式保留扩展名，避免部分系统无法识别下载后的媒体格式。
    // #ifdef MP-WEIXIN
    if (typeof wx !== "undefined" && wx.env?.USER_DATA_PATH) {
      const extension = getMediaFileExtension(url, mediaType);
      const uniqueName = `${Date.now()}-${Math.random().toString(16).slice(2)}`;
      downloadOptions.filePath = `${wx.env.USER_DATA_PATH}/aigc-${uniqueName}${extension}`;
    }
    // #endif

    uni.downloadFile(downloadOptions);
  });

const saveImageToAlbum = (filePath) =>
  new Promise((resolve, reject) => {
    uni.saveImageToPhotosAlbum({
      filePath,
      success: resolve,
      fail: reject,
    });
  });

const saveVideoToAlbum = (filePath) =>
  new Promise((resolve, reject) => {
    uni.saveVideoToPhotosAlbum({
      filePath,
      success: resolve,
      fail: reject,
    });
  });

const ensureAlbumPermission = () =>
  new Promise((resolve, reject) => {
    // #ifdef MP-WEIXIN
    uni.getSetting({
      success: ({ authSetting = {} }) => {
        const permission = authSetting["scope.writePhotosAlbum"];
        if (permission === true) {
          resolve();
          return;
        }

        if (permission === false) {
          reject({ errMsg: "scope.writePhotosAlbum permission denied" });
          return;
        }

        uni.authorize({
          scope: "scope.writePhotosAlbum",
          success: resolve,
          fail: reject,
        });
      },
      fail: reject,
    });
    // #endif

    // #ifndef MP-WEIXIN
    resolve();
    // #endif
  });

const isAlbumPermissionDenied = (error) => {
  const errorMessage = String(error?.errMsg || "").toLowerCase();
  return (
    errorMessage.includes("auth deny") ||
    errorMessage.includes("authorize:no response") ||
    errorMessage.includes("permission denied")
  );
};

const isDownloadDomainError = (error) => {
  const errorMessage = String(error?.errMsg || "").toLowerCase();
  return error?.stage === "download" && (
    errorMessage.includes("domain list") ||
    errorMessage.includes("url domain") ||
    errorMessage.includes("合法域名")
  );
};

const removeDownloadedMedia = (filePath, shouldCleanup) => {
  if (!filePath || !shouldCleanup) return;

  // #ifdef MP-WEIXIN
  wx.getFileSystemManager().unlink({
    filePath,
    fail: () => { },
  });
  // #endif
};

const promptAlbumPermission = (mediaType) => {
  const mediaName = mediaType === "video" ? "视频" : "图片";
  uni.showModal({
    title: "需要相册权限",
    content: `请在设置中允许保存${mediaName}到相册。`,
    confirmText: "去设置",
    success: ({ confirm }) => {
      if (confirm) {
        uni.openSetting();
      }
    },
  });
};

const saveResultMedia = async () => {
  if (isSaving.value) return;

  const mediaType = result.value.mediaType;
  const isVideo = mediaType === "video";
  const mediaName = isVideo ? "视频" : "图片";
  const mediaUrl = isVideo ? result.value.videoResultUrl : result.value.imageResultUrl;
  if (!mediaUrl) {
    showPlaceholderToast(`暂无可保存的${mediaName}`);
    return;
  }

  isSaving.value = true;

  let saveError = null;
  let loadingVisible = false;
  let downloadedMedia = null;
  try {
    try {
      await ensureAlbumPermission();
    } catch (error) {
      throw createMediaError("permission", error);
    }

    uni.showLoading({
      title: "保存中",
      mask: true,
    });
    loadingVisible = true;

    downloadedMedia = await downloadMedia(mediaUrl, mediaType);
    try {
      if (isVideo) {
        await saveVideoToAlbum(downloadedMedia.filePath);
      } else {
        await saveImageToAlbum(downloadedMedia.filePath);
      }
    } catch (error) {
      throw createMediaError("save", error);
    }
  } catch (error) {
    saveError = error;
    const mediaHost = String(mediaUrl).match(/^https?:\/\/([^/?#]+)/i)?.[1] || "local";
    console.error("保存AIGC媒体失败", {
      stage: error?.stage,
      errMsg: error?.errMsg,
      statusCode: error?.statusCode,
      mediaType,
      mediaHost,
    });
  } finally {
    removeDownloadedMedia(downloadedMedia?.filePath, downloadedMedia?.shouldCleanup);
    if (loadingVisible) {
      uni.hideLoading();
    }
    isSaving.value = false;
  }

  if (!saveError) {
    uni.showToast({
      title: `${mediaName}已保存`,
      icon: "success",
    });
    return;
  }

  if (isAlbumPermissionDenied(saveError)) {
    promptAlbumPermission(mediaType);
  } else if (isDownloadDomainError(saveError)) {
    showPlaceholderToast("资源下载域名未配置");
  } else if (saveError?.stage === "download") {
    showPlaceholderToast("资源下载失败，请稍后重试");
  } else {
    showPlaceholderToast(`保存${mediaName}失败`);
  }
};

const handleSave = () => {
  if (isSaving.value || pendingSaveAfterPrivacy.value) return;

  // #ifdef MP-WEIXIN
  pendingSaveAfterPrivacy.value = true;
  wx.getPrivacySetting({
    success: (res) => {
      if (res?.needAuthorization) {
        privacyContractName.value = res.privacyContractName || "隐私保护指引";
        privacyVisible.value = true;
        return;
      }

      pendingSaveAfterPrivacy.value = false;
      saveResultMedia();
    },
    fail: (error) => {
      pendingSaveAfterPrivacy.value = false;
      console.warn("检查微信隐私授权失败", error);
      showPlaceholderToast("隐私授权检查失败");
    },
  });
  // #endif

  // #ifndef MP-WEIXIN
  saveResultMedia();
  // #endif
};

const handlePrivacyAgree = () => {
  const shouldSave = pendingSaveAfterPrivacy.value;
  privacyVisible.value = false;
  pendingSaveAfterPrivacy.value = false;

  if (shouldSave) {
    saveResultMedia();
  }
};

const handlePrivacyDisagree = () => {
  privacyVisible.value = false;
  pendingSaveAfterPrivacy.value = false;
};

const handleRegenerate = async () => {
  await fetchCurrentCredit();
  regeneratePopupRef.value?.open();
};

const handleConfirmRegenerate = async () => {
  if (isRegenerating.value) return;

  isRegenerating.value = true;
  await fetchCurrentCredit();

  const balance = Number(pointBalance.value) || 0;
  if (balance < regenerateCost.value) {
    isRegenerating.value = false;
    regeneratePopupRef.value?.close();
    pointDialogVisible.value = true;
    return;
  }

  const templateItemId = String(taskDetail.value?.templateItemId || "").trim();
  const imageResultUrl = String(taskDetail.value?.imageResultUrl || "").trim();
  if (!templateItemId || !imageResultUrl) {
    isRegenerating.value = false;
    showPlaceholderToast(!templateItemId ? "缺少模板生成项" : "缺少可复用素材");
    return;
  }

  uni.showLoading({
    title: "创建中",
    mask: true,
  });

  try {
    const wxLoginCode = await getWechatLoginCode();
    const res = await createAigcGeneratorTask({
      templateItemId,
      imageUrlList: [imageResultUrl],
      wxLoginCode,
    });
    const nextTaskId = String(res?.data || "").trim();

    if (res?.code === 0 && nextTaskId) {
      regeneratePopupRef.value?.close();
      fetchCurrentCredit();
      uni.redirectTo({
        url: `/pages-aigc/progress/progress?taskId=${encodeURIComponent(nextTaskId)}`,
        fail: () => showPlaceholderToast("打开任务进度失败"),
      });
      return;
    }

    showPlaceholderToast(res?.msg || "创建任务失败");
  } catch (error) {
    console.error("重新创建AIGC生成任务失败", error);
    showPlaceholderToast("创建任务失败");
  } finally {
    uni.hideLoading();
    isRegenerating.value = false;
  }
};

const handleClosePointDialog = () => {
  pointDialogVisible.value = false;
};

const handlePointRecharge = () => {
  pointDialogVisible.value = false;
  handleRecharge();
};

const handleChangeTemplate = () => {
  uni.navigateTo({
    url: "/pages-aigc/home/home",
    fail: () => showPlaceholderToast("换个模板"),
  });
};

const handleOpenRecords = () => {
  uni.navigateTo({
    url: "/pages-aigc/record/record",
    fail: () => showPlaceholderToast("历史记录"),
  });
};
</script>

<style scoped lang="scss">
@import "./styles/index.scss";
</style>
