<template>
  <div class="page unified-shell">
    <el-card class="unified-shell" v-loading="loading">
      <div class="content">
        <div class="question-header">
          <div class="question-label">{{ TEXT.modules.knowledgeMedicalConsult.questionDesc }}</div>
          <div class="question-actions">
            <el-button v-if="canEditQuestion" type="primary" size="small" class="edit-btn" @click="openEdit">
              {{ TEXT.modules.knowledgeMedicalConsult.editQuestion }}
            </el-button>
            <el-button v-if="canConfirmResolved" type="success" size="small" @click="confirmResolved">
              {{ TEXT.modules.knowledgeMedicalConsult.confirmResolved }}
            </el-button>
          </div>
        </div>
        <div class="question-meta">
          <span class="meta-pill meta-user"
            >{{ TEXT.modules.knowledgeMedicalConsult.asker }}：{{ displayUser(item?.created_by, { members: memberMap, users: userMap }) }}</span
          >
          <span class="meta-pill meta-time">{{ TEXT.modules.knowledgeMedicalConsult.askedAt }}：{{ displayDateTime(item?.created_at) }}</span>
          <span class="meta-pill meta-category">{{ TEXT.common.labels.category }}：{{ categoryName }}</span>
          <span class="meta-pill meta-status">{{ TEXT.common.fields.status }}：{{ statusLabel }}</span>
        </div>
        <pre class="question-text">{{ item?.question }}</pre>
      </div>
      <div v-if="bestReply" class="best-answer">
        <div class="best-title">
          <span>{{ TEXT.modules.knowledgeMedicalConsult.bestAnswer }}</span>
          <el-tag type="success" size="small">{{ TEXT.modules.knowledgeMedicalConsult.adopted }}</el-tag>
        </div>
        <div class="best-meta">
          {{ displayUser(bestReply.created_by, { members: memberMap, users: userMap }) }}
          · {{ displayDateTime(bestReply.created_at) }}
        </div>
        <div class="best-content">{{ bestReply.is_deleted ? TEXT.modules.knowledgeMedicalConsult.replyDeleted : bestReply.content }}</div>
      </div>
    </el-card>

    <el-card class="mt-12 unified-shell" v-loading="repliesLoading">
      <template #header>
        <div class="reply-header">
          <span>{{ TEXT.modules.knowledgeMedicalConsult.replies }}</span>
          <span class="reply-count">{{ TEXT.modules.knowledgeMedicalConsult.replyCount.replace("{count}", String(replies.length)) }}</span>
        </div>
      </template>
      <div v-if="canReply" class="reply-form">
        <ThreadComposer
          v-model="replyContent"
          v-model:file-list="replyFiles"
          :submitting="submitting"
          :quote-item="quoteReply"
          :member-map="memberMap"
          :user-map="userMap"
          :allow-attachments="canUploadReplyAttachment"
          @submit="submitReply"
          @clear-quote="clearQuote"
        />
      </div>
      <div v-else class="reply-disabled">{{ TEXT.modules.knowledgeMedicalConsult.noReplyPermission }}</div>
      <el-divider v-if="replies.length" />
      <ThreadList
        v-if="replies.length"
        :items="replies"
        :attachments-map="replyAttachmentsMap"
        :member-map="memberMap"
        :user-map="userMap"
        :can-quote="canReply"
        :can-delete="canDeleteReply"
        :highlight-ids="bestReplyId ? [bestReplyId] : []"
        @quote="setQuote"
        @delete="removeReply"
      >
        <template #actions="{ item: r }">
          <el-tag v-if="item?.best_reply_id === r.id" type="success" size="small">{{ TEXT.modules.knowledgeMedicalConsult.bestAnswer }}</el-tag>
          <el-button v-if="canSelectBest && !r.is_deleted" type="text" size="small" @click="toggleBest(r)">
            {{ item?.best_reply_id === r.id ? TEXT.modules.knowledgeMedicalConsult.cancelBest : TEXT.modules.knowledgeMedicalConsult.setBest }}
          </el-button>
        </template>
      </ThreadList>
      <div v-else class="reply-empty">{{ TEXT.modules.knowledgeMedicalConsult.emptyReplies }}</div>
    </el-card>

    <FaqItemForm
      v-model="showForm"
      :item="editing"
      :categories="categories"
      @success="onEditSuccess"
    />
  </div>
</template>

<script setup lang="ts">
import { computed, onMounted, ref } from "vue";
import { useRoute } from "vue-router";
import { ElMessage, ElMessageBox } from "element-plus";
import type { UploadUserFile } from "element-plus";
import {
  createFaqReply,
  deleteFaqReply,
  fetchFaqItem,
  fetchFaqReplies,
  fetchFaqCategories,
  setFaqBestReply,
  setFaqStatus,
} from "../api/faqs";
import { listMembers } from "../api/members";
import { fetchAttachments, uploadAttachment } from "../api/attachments";
import { displayDateTime, displayUser, getMemberDisplayName, getUserDisplayName } from "../utils/display";
import { useAuthStore } from "../store/auth";
import { useStudyStore } from "../store/study";
import { usePermission } from "../utils/permission";
import { getAttachmentPermissionKey } from "../utils/attachmentPermissions";
import { isApiPermissionAllowed } from "../utils/apiPermissionValue";
import FaqItemForm from "../components/FaqItemForm.vue";
import ThreadComposer from "../components/ThreadComposer.vue";
import ThreadList from "../components/ThreadList.vue";
import { TEXT } from "../locales";

const route = useRoute();
const auth = useAuthStore();
const study = useStudyStore();
const item = ref<any>(null);
const loading = ref(false);
const categories = ref<any[]>([]);
const replies = ref<any[]>([]);
const repliesLoading = ref(false);
const replyContent = ref("");
const submitting = ref(false);
const quoteReply = ref<any | null>(null);
const members = ref<any[]>([]);
const showForm = ref(false);
const editing = ref<any | null>(null);
const replyFiles = ref<UploadUserFile[]>([]);
const replyAttachmentsMap = ref<Record<string, any[]>>({});

const { can } = usePermission();
const canReadCategories = computed(() => can("faq.category.read"));
const canReadMembers = computed(() => can("project.members.list"));

const canReply = computed(() => {
  if (!item.value) return false;
  return can("faq.reply");
});

const canUploadReplyAttachment = computed(() => {
  if (!item.value?.study_id) return false;
  if (auth.user?.is_admin) return true;
  const role = study.currentStudyRole || (study.currentStudy as any)?.role_in_study;
  const operationKey = getAttachmentPermissionKey("faq_replies", "create");
  return !!role && !!operationKey && isApiPermissionAllowed(study.currentPermissions?.[role]?.[operationKey]);
});

const canDeleteReply = (reply: any) => {
  if (reply.is_deleted) return false;
  if (!item.value?.study_id) return false;
  return can("faq.reply.delete");
};

const canSelectBest = computed(() => {
  if (!item.value) return false;
  return can("faq.update");
});

const canEditQuestion = computed(() => {
  if (!item.value) return false;
  return can("faq.update");
});

const canConfirmResolved = computed(() => {
  if (!item.value) return false;
  if (item.value.status === "RESOLVED") return false;
  return can("faq.update");
});

const statusLabel = computed(() => {
  return TEXT.enums.faqStatus[item.value?.status as keyof typeof TEXT.enums.faqStatus] || TEXT.enums.faqStatus.PENDING;
});

const bestReply = computed(() => {
  if (!item.value?.best_reply_id) return null;
  return replies.value.find((r) => r.id === item.value.best_reply_id) || null;
});
const bestReplyId = computed(() => item.value?.best_reply_id || null);

const memberMap = computed(() =>
  members.value.reduce<Record<string, string>>((acc, cur) => {
    const username = getMemberDisplayName(cur);
    if (cur?.user_id && username) acc[cur.user_id] = username;
    return acc;
  }, {})
);

const userMap = computed(() => {
  const map: Record<string, string> = {};
  if (auth.user?.id) {
    const name = getUserDisplayName(auth.user) || auth.user.id;
    map[auth.user.id] = name;
  }
  const push = (id?: string | null, name?: string | null) => {
    if (!id || !name) return;
    map[id] = name;
  };
  push(item.value?.created_by, item.value?.created_by_name || item.value?.created_by_display_name || item.value?.created_by_email);
  replies.value.forEach((r) => {
    push(r?.created_by, r?.created_by_name || r?.created_by_display_name || r?.created_by_email);
    push(r?.quote?.created_by, r?.quote?.created_by_name || r?.quote?.created_by_display_name || r?.quote?.created_by_email);
  });
  return map;
});

const categoryName = computed(() => {
  const cat = categories.value.find((c) => c.id === item.value?.category_id);
  return cat ? cat.name : item.value?.category_id;
});


const loadMembers = async (studyId?: string | null) => {
  if (!canReadMembers.value) {
    members.value = [];
    return;
  }
  if (!studyId) {
    members.value = [];
    return;
  }
  try {
    const { data } = await listMembers(studyId, { limit: 500 });
    members.value = Array.isArray(data) ? data : data.items || [];
  } catch {
    members.value = [];
  }
};

const loadReplies = async () => {
  const id = route.params.itemId as string;
  repliesLoading.value = true;
  try {
    const { data } = await fetchFaqReplies(id, item.value?.study_id || study.currentStudy?.id);
    replies.value = Array.isArray(data) ? data : data.items || [];
    await loadReplyAttachments();
  } catch (e: any) {
    ElMessage.error(e?.response?.data?.message || TEXT.modules.knowledgeMedicalConsult.replyLoadFailed);
  } finally {
    repliesLoading.value = false;
  }
};

const loadData = async () => {
  const id = route.params.itemId as string;
  loading.value = true;
  try {
    const { data: faqData } = await fetchFaqItem(id, study.currentStudy?.id);
    item.value = faqData;
    const questionTitle = String(faqData.question || "").trim();
    study.setViewContext({
      pageTitle: questionTitle ? questionTitle.slice(0, 24) : TEXT.modules.knowledgeMedicalConsult.detailTitle,
    });
    const categoryParams: Record<string, any> = {};
    if (faqData.study_id) {
      categoryParams.study_id = faqData.study_id;
    }
    categories.value = [];
    if (canReadCategories.value) {
      const { data: catData } = await fetchFaqCategories(categoryParams);
      categories.value = catData.items || catData || [];
    }
    await Promise.all([loadReplies(), loadMembers(faqData.study_id)]);
  } catch (e: any) {
    ElMessage.error(e?.response?.data?.message || TEXT.common.messages.loadFailed);
  } finally {
    loading.value = false;
  }
};

const setQuote = (reply: any) => {
  quoteReply.value = reply;
};

const clearQuote = () => {
  quoteReply.value = null;
};

const submitReply = async () => {
  if (!replyContent.value.trim()) {
    ElMessage.warning(TEXT.modules.knowledgeMedicalConsult.replyRequired);
    return;
  }
  if (!item.value) return;
  submitting.value = true;
  try {
    const { data } = await createFaqReply(item.value.id, item.value.study_id, {
      content: replyContent.value,
      quote_reply_id: quoteReply.value?.id || null,
    });
    const created = data as any;
    if (canUploadReplyAttachment.value && replyFiles.value.length && created?.id) {
      try {
        for (const file of replyFiles.value) {
          if (!file.raw) continue;
          await uploadAttachment(item.value.study_id, "faq_replies", created.id, file.raw as File);
        }
      } catch (e: any) {
        ElMessage.error(e?.response?.data?.message || TEXT.common.messages.uploadFailed);
      }
    }
    ElMessage.success(TEXT.modules.knowledgeMedicalConsult.replySubmitted);
    replyContent.value = "";
    quoteReply.value = null;
    replyFiles.value = [];
    loadReplies();
  } catch (e: any) {
    ElMessage.error(e?.response?.data?.message || TEXT.modules.knowledgeMedicalConsult.replyFailed);
  } finally {
    submitting.value = false;
  }
};

const removeReply = async (reply: any) => {
  if (!item.value) return;
  if (!canDeleteReply(reply)) {
    ElMessage.warning("权限不足");
    return;
  }
  const ok = await ElMessageBox.confirm(TEXT.common.confirm.delete, TEXT.common.labels.tips).catch(() => null);
  if (!ok) return;
  try {
    await deleteFaqReply(item.value.id, reply.id, item.value.study_id);
    ElMessage.success(TEXT.common.messages.deleteSuccess);
    loadReplies();
  } catch (e: any) {
    ElMessage.error(e?.response?.data?.message || TEXT.common.messages.deleteFailed);
  }
};

const toggleBest = async (reply: any) => {
  if (!item.value) return;
  if (!canSelectBest.value) {
    ElMessage.warning("权限不足");
    return;
  }
  try {
    const target = item.value.best_reply_id === reply.id ? null : reply.id;
    if (target) {
      const ok = await ElMessageBox.confirm(TEXT.modules.knowledgeMedicalConsult.confirmBestReply, TEXT.common.labels.tips).catch(() => null);
      if (!ok) return;
    }
    const { data } = await setFaqBestReply(item.value.id, item.value.study_id, { best_reply_id: target });
    item.value = data;
    ElMessage.success(target ? TEXT.modules.knowledgeMedicalConsult.bestReplySet : TEXT.modules.knowledgeMedicalConsult.bestReplyCleared);
  } catch (e: any) {
    ElMessage.error(e?.response?.data?.message || TEXT.common.messages.actionFailed);
  }
};

const confirmResolved = async () => {
  if (!item.value) return;
  if (!canConfirmResolved.value) {
    ElMessage.warning("权限不足");
    return;
  }
  try {
    const { data } = await setFaqStatus(item.value.id, item.value.study_id, { status: "RESOLVED" });
    item.value = data;
    ElMessage.success(TEXT.modules.knowledgeMedicalConsult.resolvedSuccess);
  } catch (e: any) {
    ElMessage.error(e?.response?.data?.message || TEXT.common.messages.actionFailed);
  }
};

const openEdit = () => {
  if (!canEditQuestion.value) {
    ElMessage.warning("权限不足");
    return;
  }
  editing.value = item.value;
  showForm.value = true;
};

const onEditSuccess = () => {
  showForm.value = false;
  loadData();
};

const loadReplyAttachments = async () => {
  if (!item.value?.study_id || replies.value.length === 0) {
    replyAttachmentsMap.value = {};
    return;
  }
  const entries = await Promise.all(
    replies.value.map(async (r) => {
      try {
        const { data } = await fetchAttachments(item.value.study_id, "faq_replies", r.id);
        const items = (data as any).items || data || [];
        return [r.id, items] as const;
      } catch {
        return [r.id, []] as const;
      }
    })
  );
  const next: Record<string, any[]> = {};
  entries.forEach(([id, items]) => {
    next[id] = items;
  });
  replyAttachmentsMap.value = next;
};

onMounted(() => {
  loadData();
});
</script>

<style scoped>
.page {
  padding: 16px;
}

:deep(.el-card.unified-shell) {
  border-radius: 8px !important;
}

.page :deep(.unified-shell) {
  border-radius: 8px;
}
.content {
  white-space: pre-wrap;
  line-height: 1.6;
}
.question-label {
  margin-bottom: 8px;
  font-weight: 600;
  color: #303133;
}
.question-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 6px;
}
.question-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
}
.edit-btn {
  font-weight: 600;
}
.question-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  color: #606266;
  font-size: 12px;
  margin-bottom: 8px;
}
.meta-pill {
  padding: 4px 10px;
  border-radius: 999px;
  font-weight: 500;
  border: 1px solid transparent;
}
.meta-user {
  background: #eef2ff;
  border-color: #c7d2fe;
  color: #3730a3;
}
.meta-time {
  background: #fef9c3;
  border-color: #fde68a;
  color: #92400e;
}
.meta-category {
  background: #ecfccb;
  border-color: #bef264;
  color: #3f6212;
}
.meta-status {
  background: #ecfeff;
  border-color: #a5f3fc;
  color: #155e75;
}
.confirm-row {
  margin-bottom: 8px;
}
.ml-8 {
  margin-left: 8px;
}
.mt-12 {
  margin-top: 12px;
}
.reply-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.reply-count {
  color: #909399;
  font-size: 12px;
}
.reply-form {
  margin-bottom: 12px;
}
.reply-actions {
  margin-top: 8px;
  display: flex;
  justify-content: flex-end;
}
.reply-disabled {
  color: #909399;
  font-size: 12px;
}
.reply-item {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.reply-meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.reply-actions-inline {
  display: flex;
  gap: 8px;
  align-items: center;
}
.reply-content {
  white-space: pre-wrap;
}
.danger {
  color: #f56c6c;
}
.best-answer {
  margin-top: 16px;
  padding: 12px 14px;
  border: 1px solid #e1f3d8;
  background: #f0f9eb;
  border-radius: 8px;
}
.best-title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  color: #2f6f2f;
  margin-bottom: 6px;
}
.best-meta {
  color: #606266;
  font-size: 12px;
  margin-bottom: 8px;
}
.best-content {
  white-space: pre-wrap;
}
.question-text {
  margin: 6px 0 0;
  padding: 12px 14px;
  border-radius: 8px;
  background: #f5f7ff;
  border: 1px solid #e0e7ff;
  color: #1f2a44;
  font-size: 16px;
  font-weight: 600;
}
.quote-block,
.quote-box {
  background: #f5f7fa;
  border-left: 3px solid #dcdfe6;
  padding: 8px 10px;
  border-radius: 4px;
}
.quote-meta {
  display: flex;
  justify-content: space-between;
  color: #909399;
  font-size: 12px;
  margin-bottom: 6px;
}
.quote-content {
  white-space: pre-wrap;
}
.reply-empty {
  color: #909399;
  font-size: 12px;
}
</style>
