<template>
  <div class="review-appeal-container">
    <!-- 顶部统计数据 -->
    <div class="statistics-section">
      <div class="statistics-cards">
        <div class="stat-card">
          <div class="stat-label">评价总数</div>
          <div class="stat-value">
            {{ total }}
          </div>
        </div>
        <div class="stat-card">
          <div class="stat-label">新增差评数</div>
          <div class="stat-value">
            {{ statistics.badTextReviews }}
          </div>
        </div>
        <div class="stat-card">
          <div class="stat-label">新增好评数</div>
          <div class="stat-value">
            {{ statistics.badImageReviews }}
          </div>
        </div>
        <div class="stat-card">
          <div class="stat-label">新增中评数</div>
          <div class="stat-value">
            {{ statistics.neutralReviews }}
          </div>
        </div>
        <div class="stat-card">
          <div class="stat-label">评论回复率</div>
          <div class="stat-value highlight">
            {{ statistics.abnormalRate }}
          </div>
        </div>
      </div>
    </div>

    <!-- 评价列表区域 -->
    <div class="review-list-section">
      <div class="section-header">
        <div class="section-title">
          评价列表 <el-button type="primary" style="float: right" @click="goToAppealHistory"> 申诉历史 </el-button>
        </div>
        <div class="time-filter">
          <span>评论时间：</span>
          <el-select v-model="timeFilter" placeholder="请选择" class="time-filter-select" @change="handleTimeFilterChange">
            <el-option label="全部" value="" />
            <el-option label="30天" value="30" />
          </el-select>
        </div>
        <el-tabs v-model="activeTab" @tab-click="handleTabClick">
          <el-tab-pane :label="`全部 (${tabCounts.all})`" name="0" />
          <el-tab-pane :label="`待回复差评 (${tabCounts.noReplyCount})`" name="pending" />
          <el-tab-pane :label="`差评 (${tabCounts.bad})`" name="3" />
          <el-tab-pane :label="`好评 (${tabCounts.good})`" name="1" />
          <el-tab-pane :label="`中评 (${tabCounts.neutral})`" name="2" />
        </el-tabs>
      </div>

      <!-- 评论卡片列表 -->
      <div v-if="reviewList.length > 0" class="review-cards">
        <div v-for="review in reviewList" :key="review.id" class="review-card">
          <div class="review-header">
            <div class="user-info">
              <el-avatar :src="review.userAvatar" :size="40">
                <el-icon><User /></el-icon>
              </el-avatar>
              <div class="user-details">
                <div class="user-name">
                  {{ review.isAnonymous == 1 || !review.userName ? "匿名用户" : review.userName }}
                </div>
                <el-rate v-model="review.score" disabled />
              </div>
            </div>
            <div class="review-time">
              {{ (review.createdTime || "").replace(/-/g, "/") }}
            </div>
          </div>

          <div class="review-content">
            {{ review.commentContent }}
          </div>

          <div v-for="(itm, idx) in review.storeComment" :key="idx">
            <div class="sjhf">商家回复： {{ itm.commentContent }}</div>
          </div>

          <div v-if="review.media && review.media.length > 0" class="review-media">
            <template v-for="(m, index) in review.media" :key="index">
              <el-image
                v-if="m.type === 'image'"
                :src="m.url"
                :preview-src-list="review.images"
                :initial-index="getMediaImageIndex(review.media, Number(index))"
                fit="cover"
                class="media-item review-image"
              />
              <div v-else class="media-item media-video-wrap" @click="openVideoPreview(m.url)">
                <video
                  :src="m.url"
                  class="video-thumb"
                  preload="metadata"
                  muted
                  playsinline
                  @loadeddata="onVideoLoadedData($event)"
                />
                <div class="video-mask">
                  <el-icon class="video-play-icon">
                    <VideoPlay />
                  </el-icon>
                </div>
              </div>
            </template>
          </div>

          <div class="review-footer">
            <el-button type="warning" link v-if="review.appealStatus == 0"> 审核中 </el-button>
            <el-button
              type="danger"
              link
              v-if="review.appealStatus != 0"
              :disabled="review.appealFlag == 1 && review.appealStatus != 1 ? true : false"
              @click="delReviewAppeal(review)"
            >
              申诉删除
            </el-button>

            <el-button type="primary" link @click="openReplayDialog(review)" v-if="!hasStoreReply(review)"> 回复 </el-button>
          </div>
        </div>
      </div>

      <!-- 空状态 -->
      <el-empty v-else description="暂无评论数据" />

      <!-- 分页 -->
      <div v-if="total > 0" class="pagination-wrapper">
        <el-pagination
          v-model:current-page="pageNum"
          v-model:page-size="pageSize"
          :page-sizes="[10, 20, 30, 50]"
          :total="total"
          layout="total, sizes, prev, pager, next, jumper"
          background
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
        />
      </div>
    </div>

    <!-- 申诉提交对话框 -->
    <el-dialog v-model="appealDialogVisible" title="申诉删除" width="600px" @close="closeAppealDialog">
      <el-form ref="appealFormRef" :model="appealFormData" :rules="appealFormRules" label-width="100px">
        <el-form-item label="申诉原因" prop="reason">
          <el-input
            v-model="appealFormData.reason"
            type="textarea"
            :rows="4"
            placeholder="请输入申诉原因"
            maxlength="300"
            show-word-limit
          />
        </el-form-item>

        <el-form-item label="申诉凭证" prop="images">
          <el-upload
            v-model:file-list="appealFormData.fileList"
            list-type="picture-card"
            :limit="6"
            :http-request="handleUpload"
            :on-preview="handlePreview"
            :on-remove="handleRemove"
            :on-success="handleUploadSuccess"
            accept="image/*"
          >
            <el-icon><Plus /></el-icon>
          </el-upload>
        </el-form-item>
      </el-form>

      <template #footer>
        <el-button @click="closeAppealDialog"> 取消 </el-button>
        <el-button type="primary" @click="submitAppeal"> 确定 </el-button>
      </template>
    </el-dialog>

    <!-- 回复对话框 -->
    <el-dialog v-model="replyDialogVisible" title="回复评价" width="600px" @close="closeReplyDialog">
      <el-form ref="replyFormRef" :model="replyFormData" :rules="replyFormRules" label-width="100px">
        <el-form-item label="回复内容" prop="content">
          <el-input
            v-model="replyFormData.content"
            type="textarea"
            :rows="6"
            placeholder="请输入回复内容"
            maxlength="300"
            show-word-limit
          />
        </el-form-item>
      </el-form>

      <template #footer>
        <el-button @click="closeReplyDialog"> 取消 </el-button>
        <el-button type="primary" @click="submitReply"> 提交回复 </el-button>
      </template>
    </el-dialog>

    <!-- 视频预览弹窗 -->
    <el-dialog
      v-model="videoPreviewVisible"
      title="视频预览"
      width="80%"
      max-width="720px"
      destroy-on-close
      align-center
      @closed="closeVideoPreview"
    >
      <video v-if="videoPreviewUrl" :src="videoPreviewUrl" controls autoplay style="width: 100%; max-height: 70vh" />
    </el-dialog>
  </div>
</template>

<script setup lang="ts" name="reviewAppeal">
import { ref, reactive, onMounted } from "vue";
import { useRouter } from "vue-router";
import { ElMessage } from "element-plus";
import { User, Plus, VideoPlay } from "@element-plus/icons-vue";
import type { FormInstance, FormRules, UploadUserFile } from "element-plus";
import { getList, addAppealNew, saveComment2, getRatingCount } from "@/api/modules/newLoginApi";
import { uploadFileToOss } from "@/api/upload.js";
import { localGet } from "@/utils";
import { useUserStore } from "@/stores/modules/user";

const router = useRouter();
const userStore = useUserStore();

// 店铺名称
const storeName = ref("重庆老火锅");

// 统计数据
const statistics = reactive({
  totalReviews: 0,
  badTextReviews: 0,
  badImageReviews: 0,
  neutralReviews: 0,
  abnormalRate: "0%"
});

// 标签页计数（由 getRatingCount 接口填充）
const tabCounts = reactive({
  all: 0,
  pending: 0,
  bad: 0,
  good: 0,
  neutral: 0,
  noReplyCount: 0
});

// 当前激活的标签
const activeTab = ref("0");

// 评论时间筛选
const timeFilter = ref("");

// 评论列表
const reviewList = ref<any[]>([]);

// 分页参数
const pageNum = ref(1);
const pageSize = ref(10);
const total = ref(0);

// 申诉提交对话框
const appealDialogVisible = ref(false);
const appealFormRef = ref<FormInstance>();
const currentReviewId = ref("");

const appealFormData = reactive({
  reason: "",
  images: [] as string[], // 申诉凭证：OSS 图片 URL（与 fileList 顺序一致）
  fileList: [] as UploadUserFile[]
});
const hasStoreReply = (review: any) => {
  return review?.storeComment && review.storeComment.length > 0;
};

/** 在 media 列表中，当前项在「仅图片」列表中的下标，用于 el-image initial-index */
const getMediaImageIndex = (media: { url: string; type: string }[], currentIndex: number): number => {
  let idx = 0;
  for (let i = 0; i < currentIndex; i++) if (media[i].type === "image") idx++;
  return idx;
};

const videoPreviewVisible = ref(false);
const videoPreviewUrl = ref("");
const openVideoPreview = (url: string) => {
  videoPreviewUrl.value = url;
  videoPreviewVisible.value = true;
};
const closeVideoPreview = () => {
  videoPreviewUrl.value = "";
  videoPreviewVisible.value = false;
};
const onVideoLoadedData = (e: Event) => {
  const video = e.target as HTMLVideoElement;
  if (video) {
    video.currentTime = 0;
    video.pause();
  }
};

const appealFormRules = reactive<FormRules>({
  reason: [{ required: true, message: "请输入申诉原因", trigger: "blur" }],
  images: [{ required: true, message: "请上传申诉凭证", trigger: "blur" }]
});

// 回复对话框
const replyDialogVisible = ref(false);
const replyFormRef = ref<FormInstance>();
const currentReplyReview = ref<any>(null);

const replyFormData = reactive({
  content: ""
});

const replyFormRules = reactive<FormRules>({
  content: [{ required: true, message: "请输入回复内容", trigger: "blur" }]
});

// 标签页切换
const handleTabClick = (tab: any) => {
  // 获取点击的标签页的 name 值
  const tabName = tab.paneName || tab.props?.name || activeTab.value;
  loadReviewList(tabName, true);
};

// 跳转到申诉历史
const goToAppealHistory = () => {
  router.push("/dynamicManagement/reviewAppealHistory");
};

// 评论时间筛选变化
const handleTimeFilterChange = () => {
  loadReviewList(activeTab.value, true);
};

// 与商家端一致：兼容 code 0 / 200，从 getRatingCount 取 totalCount、goodCount、midCount、badCount、pending、replyRate
const loadStatistics = async () => {
  try {
    const ratingCountRes: any = await getRatingCount({
      businessId: localGet("createdId"),
      businessType: 1
    });
    const isOk = ratingCountRes?.code === 200 || ratingCountRes?.code === 0;
    const ratingCount = isOk ? (ratingCountRes.data ?? ratingCountRes) : null;
    const rc = ratingCount as Record<string, number | undefined> | null;
    tabCounts.all = rc?.totalCount ?? 0;
    tabCounts.good = rc?.goodCount ?? 0;
    tabCounts.neutral = rc?.midCount ?? 0;
    tabCounts.bad = rc?.badCount ?? 0;
    tabCounts.pending = rc?.pending ?? 0;
    tabCounts.noReplyCount = rc?.noReplyCount ?? 0;

    statistics.totalReviews = tabCounts.all;
    statistics.badTextReviews = tabCounts.bad;
    statistics.badImageReviews = tabCounts.good;
    statistics.neutralReviews = tabCounts.neutral;

    if (rc?.replyRate != null) {
      statistics.abnormalRate = Number(rc.replyRate).toFixed(2) + "%";
    } else {
      const totalCount = tabCounts.all;
      const repliedCount = rc?.repliedCount ?? Math.max(0, totalCount - tabCounts.pending);
      if (totalCount > 0) {
        statistics.abnormalRate = ((repliedCount / totalCount) * 100).toFixed(2) + "%";
      } else {
        statistics.abnormalRate = "0%";
      }
    }
  } catch (error) {
    console.error("获取统计数据失败", error);
  }
};

const VIDEO_EXT = [".mp4", ".mov", ".avi", ".wmv", ".flv", ".mkv", ".webm", ".m4v"];
const isVideoUrl = (url: string) => {
  const lower = (url || "").toLowerCase();
  return VIDEO_EXT.some(ext => lower.includes(ext));
};

// 与商家端一致：将 commonRating/getList 返回的单条转为列表展示格式；imageUrls 中区分图片与视频，视频用首帧展示
function transformRatingData(item: any): any {
  if (!item || typeof item !== "object" || item.id == null) return null;
  let urls: string[] = [];
  if (item.imageUrls) {
    const raw =
      typeof item.imageUrls === "string" && item.imageUrls.trim()
        ? item.imageUrls.split(",").filter((u: string) => u?.trim())
        : Array.isArray(item.imageUrls)
          ? item.imageUrls
          : [];
    urls = raw.map((u: string) => (u && u.trim()) || "").filter(Boolean);
  }
  const media = urls.map(url => ({ url, type: isVideoUrl(url) ? ("video" as const) : ("image" as const) }));
  const images = media.filter(m => m.type === "image").map(m => m.url);
  let storeComment: { commentContent: string; createdTime?: string }[] = [];
  if (item.childCommonComments) {
    const list = Array.isArray(item.childCommonComments)
      ? item.childCommonComments
      : Object.values(item.childCommonComments || {});
    storeComment = list
      .filter((c: any) => c && Number(c.commentType) === 2)
      .map((c: any) => ({
        commentContent: c.content || c.commentContent || "",
        createdTime: c.createdTime || ""
      }));
  }
  return {
    id: item.id,
    commentContent: item.content ?? item.commentContent ?? "",
    score: item.score ?? 0,
    images,
    media,
    userAvatar: item.userImage ?? item.userAvatar ?? "",
    userName: item.userName ?? (item.isAnonymous === 1 ? "匿名用户" : "用户"),
    createdTime: item.createdTime ?? "",
    isAnonymous: item.isAnonymous ?? 0,
    storeComment,
    appealStatus: item.appealStatus !== undefined && item.appealStatus !== null ? item.appealStatus : null,
    appealFlag: item.appealFlag !== undefined ? item.appealFlag : item.appealStatus != null ? 1 : 0
  };
}

// 加载评论列表（与商家端 getRatingList 参数一致：pageNum、pageSize、businessType、businessId、userId、searchScore、days、replyStatus）
const loadReviewList = async (commentLevel?: string | number, resetPage = false) => {
  try {
    if (resetPage) pageNum.value = 1;

    const level = commentLevel !== undefined ? commentLevel : activeTab.value;
    const isPending = level === "pending";

    const params: Record<string, any> = {
      pageNum: pageNum.value,
      pageSize: pageSize.value,
      businessType: 1,
      businessId: localGet("createdId"),
      userId: userStore.userInfo?.userId || userStore.userInfo?.id || ""
      // replyStatus: 2
    };

    const levelNum = isPending ? 3 : Number(level);
    if (levelNum !== 0) params.searchScore = levelNum;
    if (timeFilter.value) params.days = timeFilter.value;
    if (isPending) params.replyStatus = 2;

    const res: any = await getList(params);

    const isOk = res?.code === 200 || res?.code === 0;
    const data = res?.data ?? res;
    const records = data?.records ?? (Array.isArray(data) ? data : []);
    const totalCount = data?.total ?? res?.total ?? 0;

    if (isOk && (records.length > 0 || totalCount >= 0)) {
      reviewList.value = records.map((item: any) => transformRatingData(item)).filter(Boolean);
      total.value = totalCount;
    } else {
      reviewList.value = [];
      total.value = 0;
      if (!isOk && res?.msg) ElMessage.error(res.msg);
    }
  } catch (error: any) {
    console.error("获取评论列表失败", error);
    reviewList.value = [];
    total.value = 0;
    ElMessage.error(error?.message || error?.msg || "获取评论列表失败");
  }
};

// 分页大小变化
const handleSizeChange = (val: number) => {
  pageSize.value = val;
  pageNum.value = 1;
  loadReviewList();
};

// 页码变化
const handleCurrentChange = (val: number) => {
  pageNum.value = val;
  loadReviewList();
};

// 申诉删除
const delReviewAppeal = (review: any) => {
  currentReviewId.value = review.id;
  appealDialogVisible.value = true;
};
//回复评论
// 打开回复对话框
const openReplayDialog = (review: any) => {
  currentReplyReview.value = review;
  replyDialogVisible.value = true;
};

// 关闭回复对话框
const closeReplyDialog = () => {
  replyDialogVisible.value = false;
  replyFormRef.value?.resetFields();
  Object.assign(replyFormData, {
    content: ""
  });
  currentReplyReview.value = null;
};

// 提交回复（与商家端 saveComment 参数一致：businessId=店铺ID、replyId=评论ID、commentContent、storeId、userId、phoneId、businessType）
const submitReply = async () => {
  if (!replyFormRef.value || !currentReplyReview.value) return;

  await replyFormRef.value.validate(async (valid: boolean) => {
    if (!valid) return;
    try {
      const phone = userStore.userInfo?.phone || "";
      const phoneId = phone.startsWith("store_") ? phone : `store_${phone}`;
      const storeId = userStore.userInfo?.storeId || localGet("createdId") || "";

      const params = {
        businessId: storeId,
        businessType: "1",
        userId: String(userStore.userInfo?.userId ?? userStore.userInfo?.id ?? ""),
        storeId,
        commentContent: replyFormData.content,
        phoneId,
        replyId: currentReplyReview.value.id
      };

      const res: any = await saveComment2(params);
      const isOk = res?.code === 200 || res?.code === 0;

      if (isOk) {
        ElMessage.success("回复提交成功");
        closeReplyDialog();
        loadReviewList();
        loadStatistics();
      } else {
        ElMessage.error(res?.message || res?.msg || "回复提交失败");
      }
    } catch (error: any) {
      console.error("回复提交失败:", error);
      ElMessage.error(error?.message || "回复提交失败");
    }
  });
};

// 关闭申诉对话框
const closeAppealDialog = () => {
  appealDialogVisible.value = false;
  appealFormRef.value?.resetFields();
  Object.assign(appealFormData, {
    reason: "",
    images: [],
    fileList: []
  });
};

// 提交申诉（与商家端 addAppealNew 一致：FormData 含 appealReason、storeId、commentId、file_0/file_1...；凭证已为 OSS 地址时按 URL 字符串提交）
const submitAppeal = async () => {
  if (!appealFormRef.value) return;

  await appealFormRef.value.validate(async (valid: boolean) => {
    if (!valid) return;
    try {
      const geekerUser = localGet("geeker-user");
      const storeId = geekerUser?.userInfo?.storeId ?? localGet("createdId") ?? "";

      const formData = new FormData();
      formData.append("appealReason", appealFormData.reason);
      formData.append("storeId", String(storeId));
      formData.append("commentId", String(currentReviewId.value));
      appealFormData.images.forEach((url: string, index: number) => {
        formData.append(`file_${index}`, url);
      });

      const res: any = await addAppealNew(formData);
      const result = res?.data?.result ?? res?.result;

      if (result === 0) {
        ElMessage.success("申诉提交成功");
        const review = reviewList.value.find((r: any) => String(r.id) === String(currentReviewId.value));
        if (review) review.appealFlag = 1;
        loadStatistics();
      } else if (result === 2) {
        ElMessage.warning("申诉已存在");
      } else if (result === 3) {
        ElMessage.warning("申诉理由包含敏感词，请修改后重试");
      } else if (result === 4) {
        ElMessage.warning("申诉理由超过300字限制");
      } else {
        ElMessage.error(res?.msg || "申诉提交失败");
      }
      closeAppealDialog();
    } catch (error: any) {
      ElMessage.error(error?.message || "申诉提交失败");
    }
  });
};

// 图片预览
const handlePreview = (file: UploadUserFile) => {
  console.log("preview", file);
};

// 移除图片
const handleRemove = (file: UploadUserFile, fileList: UploadUserFile[]) => {
  const index = appealFormData.fileList.findIndex(f => f.uid === file.uid);
  if (index !== -1) {
    appealFormData.images.splice(index, 1);
  }
  appealFormData.fileList = fileList;
};

/** OSS 直传后交给 el-upload 展示网络地址 */
const handleUpload = async (options: any) => {
  const { file, onSuccess, onError } = options;

  try {
    const url = await uploadFileToOss(file as File, "image");
    if (!url) {
      throw new Error("上传失败，未返回地址");
    }
    appealFormData.images.push(url);
    onSuccess({ url });
  } catch (error: any) {
    onError(error);
    // 错误提示由 upload.js 内 ElMessage 处理
  }
};

const handleUploadSuccess = (_response: any, _file: any) => {
  // 列表与 images 已在 handleUpload 中维护
};

// 初始化
onMounted(() => {
  loadStatistics(); // 加载统计数据
  loadReviewList(); // 加载评论列表
});
</script>

<style lang="scss" scoped>
.review-appeal-container {
  min-height: calc(100vh - 120px);
  background: #f5f7fa;

  // 统计数据区域
  .statistics-section {
    padding: 20px;
    margin-bottom: 20px;
    background: #ffffff;
    border-radius: 8px;
    .statistics-cards {
      display: flex;
      gap: 20px;
      margin-bottom: 16px;
      .stat-card {
        flex: 1;
        padding: 16px;
        text-align: center;
        background: #f5f7fa;
        border-radius: 4px;
        .stat-label {
          margin-bottom: 8px;
          font-size: 14px;
          color: #909399;
        }
        .stat-value {
          font-size: 24px;
          font-weight: 600;
          color: #303133;
          &.highlight {
            color: #f56c6c;
          }
        }
      }
    }
  }

  // 评价列表区域
  .review-list-section {
    padding: 20px;
    background: #ffffff;
    border-radius: 8px;
    .section-header {
      margin-bottom: 20px;
      .section-title {
        margin-bottom: 16px;
        font-size: 16px;
        font-weight: 600;
        color: #303133;
      }
      .time-filter {
        margin-bottom: 10px;
        font-size: 14px;
        .time-filter-select {
          width: 120px;
        }
      }
    }

    // 评论卡片
    .review-cards {
      display: flex;
      flex-direction: column;
      gap: 16px;
      .review-card {
        padding: 16px;
        border: 1px solid #e4e7ed;
        border-radius: 8px;
        .review-header {
          display: flex;
          justify-content: space-between;
          margin-bottom: 12px;
          .user-info {
            display: flex;
            gap: 12px;
            align-items: center;
            .user-details {
              .user-name {
                margin-bottom: 4px;
                font-size: 14px;
                font-weight: 600;
                color: #303133;
              }
            }
          }
          .review-time {
            font-size: 13px;
            color: #909399;
          }
        }
        .review-content {
          margin-bottom: 12px;
          font-size: 14px;
          line-height: 1.6;
          color: #606266;
        }
        .sjhf {
          padding-bottom: 10px;
          font-size: 14px;
          color: #606266;
        }
        .review-media {
          display: flex;
          flex-wrap: wrap;
          gap: 8px;
          margin-bottom: 12px;
          .media-item {
            flex-shrink: 0;
            width: 80px;
            height: 80px;
            overflow: hidden;
            border-radius: 4px;
          }
          .review-image {
            object-fit: cover;
          }
          .media-video-wrap {
            position: relative;
            cursor: pointer;
            background: #000000;
            .video-thumb {
              display: block;
              width: 100%;
              height: 100%;
              object-fit: cover;
            }
            .video-mask {
              position: absolute;
              inset: 0;
              display: flex;
              align-items: center;
              justify-content: center;
              background: rgb(0 0 0 / 35%);
              .video-play-icon {
                font-size: 28px;
                color: #ffffff;
              }
            }
          }
        }
        .review-footer {
          display: flex;
          gap: 16px;
          padding-top: 12px;
          border-top: 1px solid #e4e7ed;
        }
      }
    }

    // 分页
    .pagination-wrapper {
      display: flex;
      justify-content: flex-end;
      padding-top: 20px;
      margin-top: 20px;
      border-top: 1px solid #e4e7ed;
    }
  }
}
</style>
