<template>
  <div class="page">
    <el-card shadow="never" class="main-content-card unified-shell">
      <div class="filter-container unified-action-bar">
        <el-form :inline="true" :model="filters" class="filter-form">
          <el-form-item label="" class="filter-item-form">
            <el-select v-model="filters.entityType" clearable :placeholder="TEXT.modules.adminAuditLogs.filterEntityType" @change="loadLogs" class="filter-select-comp">
              <el-option v-for="opt in entityTypeOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
            </el-select>
          </el-form-item>
          <el-form-item label="" class="filter-item-form">
            <el-select v-model="filters.eventType" clearable :placeholder="TEXT.modules.adminAuditLogs.filterEvent" @change="loadLogs" class="filter-select-comp">
              <el-option v-for="opt in eventTypeOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
            </el-select>
          </el-form-item>
          <el-form-item label="" class="filter-item-form">
            <el-select v-model="filters.operatorId" clearable :placeholder="TEXT.modules.adminAuditLogs.filterOperator" filterable @change="loadLogs" class="filter-select-comp">
              <el-option v-for="u in userOptions" :key="u.value" :label="u.label" :value="u.value" />
            </el-select>
          </el-form-item>
          <el-form-item label="" class="filter-item-form">
            <el-select v-model="filters.result" clearable :placeholder="TEXT.modules.adminAuditLogs.filterResult" @change="loadLogs" style="width: 120px">
              <el-option :label="TEXT.audit.resultSuccess" value="SUCCESS" />
              <el-option :label="TEXT.audit.resultFail" value="FAIL" />
            </el-select>
          </el-form-item>
          <el-form-item label="" class="filter-item-form">
            <el-date-picker
              v-model="filters.range"
              type="daterange"
              unlink-panels
              :start-placeholder="TEXT.modules.adminAuditLogs.rangeStart"
              :end-placeholder="TEXT.modules.adminAuditLogs.rangeEnd"
              format="YYYY-MM-DD"
              value-format="YYYY-MM-DD"
              class="date-range-picker-comp"
              @change="loadLogs"
            />
          </el-form-item>
          <div class="filter-spacer"></div>
          <div class="ctms-action-group">
            <el-button v-if="isAdmin" type="warning" plain size="small" :loading="exportLoading" @click="confirmExport('system')">
              {{ TEXT.modules.adminAuditLogs.exportSystem }}
            </el-button>
            <el-button v-if="canProjectExport" type="warning" plain size="small" :loading="exportLoading" @click="confirmExport('project')">
              {{ TEXT.modules.adminAuditLogs.exportProject }}
            </el-button>
          </div>
        </el-form>
      </div>
      <div class="unified-section table-section">
        <el-table :data="logs" v-loading="loading" style="width: 100%" stripe>
          <el-table-column prop="timestamp" :label="TEXT.modules.adminAuditLogs.columns.time" width="180" align="center">
            <template #default="scope">
              <span class="text-gray-500">{{ displayDateTime(scope.row.timestamp) }}</span>
            </template>
          </el-table-column>
          <el-table-column prop="actorName" :label="TEXT.modules.adminAuditLogs.columns.actor" width="140" />
          <el-table-column prop="actorRoleLabel" :label="TEXT.common.labels.role" width="120" />
          <el-table-column prop="eventLabel" :label="TEXT.modules.adminAuditLogs.columns.event" width="160">
            <template #default="scope">
               <el-tag effect="plain">{{ scope.row.eventLabel }}</el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="actionText" :label="TEXT.modules.adminAuditLogs.columns.action" min-width="180" />
          <el-table-column :label="TEXT.modules.adminAuditLogs.columns.target" min-width="180">
            <template #default="scope">
              <span v-if="scope.row.targetTypeLabel">
                <strong>{{ scope.row.targetTypeLabel }}</strong>
                <span class="text-gray-500" v-if="scope.row.targetName">（{{ scope.row.targetName }}）</span>
              </span>
              <span v-else>{{ TEXT.common.fallback }}</span>
            </template>
          </el-table-column>
          <el-table-column :label="TEXT.modules.adminAuditLogs.columns.diff" min-width="260">
            <template #default="scope">
              <div v-if="scope.row.diffText?.length" class="diff-container">
                <div v-for="(line, idx) in scope.row.diffText" :key="idx" class="diff-line">{{ line }}</div>
              </div>
              <span v-else class="text-gray-400">{{ TEXT.audit.emptyValue }}</span>
            </template>
          </el-table-column>
          <el-table-column :label="TEXT.modules.adminAuditLogs.columns.result" width="100" align="center">
            <template #default="scope">
              <el-tag :type="scope.row.result === 'SUCCESS' ? 'success' : 'danger'" effect="dark" size="small">
                {{ scope.row.resultLabel }}
              </el-tag>
            </template>
          </el-table-column>
        </el-table>
        <el-pagination
          class="pagination"
          layout="prev, pager, next"
          :page-size="pageSize"
          :current-page="page"
          :total="total"
          @current-change="onPageChange"
        />
      </div>
    </el-card>
  </div>
</template>

<script setup lang="ts">
import { computed, onMounted, ref } from "vue";
import { useRouter } from "vue-router";
import { ElMessage, ElMessageBox } from "element-plus";
import { fetchAuditLogs } from "../../api/auditLogs";
import { fetchUsers } from "../../api/users";
import { listMembers } from "../../api/members";
import { auditDict, normalizeAuditEvent } from "../../audit";
import { useStudyStore } from "../../store/study";
import { useAuthStore } from "../../store/auth";
import { roleDict, getDictLabel } from "../../dictionaries";
import { exportAuditCsv } from "../../audit/export/auditExportService";
import { logAudit } from "../../audit";
import { displayDateTime } from "../../utils/display";
import { TEXT } from "../../locales";

const buildLogKey = (log: any) => {
  if (log.id) return `id:${log.id}`;
  return `${log.action || log.eventType || "event"}-${log.entity_id || log.entityId || ""}-${log.created_at || log.timestamp || ""}`;
};

const dedupeLogs = (list: any[]) => {
  const seen = new Set<string>();
  const result: any[] = [];
  list.forEach((log) => {
    const key = buildLogKey(log);
    if (seen.has(key)) return;
    seen.add(key);
    result.push(log);
  });
  return result;
};

const study = useStudyStore();
const auth = useAuthStore();
const router = useRouter();

const loading = ref(false);
const exportLoading = ref(false);
const rawLogs = ref<any[]>([]);
const logs = ref<any[]>([]);
const users = ref<any[]>([]);
const page = ref(1);
const pageSize = 20;
const total = ref(0);

const filters = ref({
  entityType: "",
  eventType: "",
  operatorId: "",
  result: "",
  range: [],
});

const eventTypeOptions = Object.entries(auditDict).map(([value, cfg]) => ({
  value,
  label: cfg.label,
}));
const entityTypeOptions = [
  { value: "study_setup_config", label: "立项配置" },
  { value: "study", label: "项目" },
  { value: "subject", label: "参与者" },
  { value: "site", label: "中心" },
  { value: "finance", label: "费用" },
  { value: "drug_shipment", label: "药品流向" },
  { value: "audit_log", label: "审计日志" },
];
const userOptions = computed(() => users.value.map((u: any) => ({ label: u.username, value: u.id })));
const isAdmin = computed(() => auth.user?.role === "ADMIN");
const canProjectExport = computed(() => !!study.currentStudy && auth.user?.role === "ADMIN");

const ensureAccess = () => {
  const role = auth.user?.role;
  if (role !== "ADMIN") {
    router.replace("/admin/users");
  }
};

const loadUsers = async () => {
  try {
    if (auth.user?.role === "ADMIN") {
      const { data } = await fetchUsers({ limit: 500 });
      users.value = (data as any).items || data || [];
    } else if (study.currentStudy) {
      // 非管理员，尝试加载项目成员作为备选
      const { data } = await listMembers(study.currentStudy.id, { limit: 500 });
      const items = Array.isArray(data) ? data : (data as any).items || [];
      users.value = items.map((m: any) => ({
        id: m.user_id,
        username: m.user?.display_name || m.user?.full_name || m.user?.username || m.username,
      }));
    }
  } catch {
    users.value = [];
  }
};

const loadLogs = async () => {
  if (!study.currentStudy) return;
  loading.value = true;
  try {
    const params: Record<string, any> = {
      skip: (page.value - 1) * pageSize,
      limit: pageSize,
      entity_type: filters.value.entityType || undefined,
      action: filters.value.eventType || undefined,
      operator_id: filters.value.operatorId || undefined,
    };
    const { data } = await fetchAuditLogs(study.currentStudy.id, params);
    const items = Array.isArray(data) ? data : (data as any).items || [];
    const local = loadLocalLogs();
    const merged = dedupeLogs([...items, ...local]);
    rawLogs.value = merged;
    total.value = (data as any).total || merged.length;
    enrichLogs();
  } catch (e: any) {
    ElMessage.error(e?.response?.data?.message || TEXT.modules.adminAuditLogs.loadFailed);
  } finally {
    loading.value = false;
  }
};

const loadLocalLogs = () => {
  try {
    const key = `audit_local_${study.currentStudy?.id || "global"}`;
    const raw = localStorage.getItem(key);
    if (!raw) return [];
    const list = JSON.parse(raw);
    return Array.isArray(list) ? list : [];
  } catch {
    return [];
  }
};

const enrichLogs = () => {
  const userMap = users.value.reduce<Record<string, string>>((acc, cur) => {
    acc[cur.id] = cur.username;
    return acc;
  }, {});
  const filtered = rawLogs.value.filter((log) => {
    if (filters.value.result && (log.result || "SUCCESS") !== filters.value.result) return false;
    if (filters.value.range?.length === 2) {
      const ts = new Date(log.created_at);
      const start = new Date(filters.value.range[0]);
      const end = new Date(filters.value.range[1]);
      if (ts < start || ts > end) return false;
    }
    return true;
  });
  logs.value = filtered
    .map((log) => normalizeAuditEvent(log, userMap))
    .sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
  if (users.value.length === 0) {
    const byActor = new Map<string, string>();
    logs.value.forEach((log) => {
      if (!byActor.has(log.actorId)) {
        byActor.set(log.actorId, log.actorName || log.actorId);
      }
    });
    users.value = Array.from(byActor.entries()).map(([id, username]) => ({ id, username }));
  }
};

const onPageChange = (p: number) => {
  page.value = p;
  loadLogs();
};

const fetchAllForExport = async () => {
  if (!study.currentStudy) return [];
  exportLoading.value = true;
  try {
    const params: Record<string, any> = {
      skip: 0,
      limit: 2000,
      entity_type: filters.value.entityType || undefined,
      action: filters.value.eventType || undefined,
      operator_id: filters.value.operatorId || undefined,
    };
    const { data } = await fetchAuditLogs(study.currentStudy.id, params);
    const items = Array.isArray(data) ? data : (data as any).items || [];
    const local = loadLocalLogs();
    const merged = dedupeLogs([...items, ...local]);
    const userMap = users.value.reduce<Record<string, string>>((acc, cur) => {
      acc[cur.id] = cur.username;
      return acc;
    }, {});
    const filtered = merged.filter((log) => {
      if (filters.value.range?.length === 2) {
        const ts = new Date(log.created_at);
        const start = new Date(filters.value.range[0]);
        const end = new Date(filters.value.range[1]);
        if (ts < start || ts > end) return false;
      }
      return true;
    });
    return filtered.map((log) => normalizeAuditEvent(log, userMap));
  } catch (e: any) {
    ElMessage.error(e?.response?.data?.message || TEXT.modules.adminAuditLogs.exportLoadFailed);
    return [];
  } finally {
    exportLoading.value = false;
  }
};

const confirmExport = async (scope: "system" | "project") => {
  const ok = await ElMessageBox.confirm(
    TEXT.modules.adminAuditLogs.exportConfirm,
    TEXT.modules.adminAuditLogs.exportConfirmTitle,
    { type: "warning", confirmButtonText: TEXT.common.actions.confirm, cancelButtonText: TEXT.common.actions.cancel }
  ).catch(() => null);
  if (!ok) return;
  const events = await fetchAllForExport();
  if (!events.length) {
    ElMessage.warning(TEXT.modules.adminAuditLogs.exportEmpty);
    return;
  }
  const fileName =
    scope === "system"
      ? `${TEXT.modules.adminAuditLogs.exportSystemName}_${new Date().toISOString().slice(0, 10)}`
      : `${TEXT.modules.adminAuditLogs.exportProjectName}_${study.currentStudy?.code || ""}_${new Date().toISOString().slice(0, 10)}`;
  exportAuditCsv(events, { fileName });
  logAudit(scope === "system" ? "AUDIT_EXPORT_SYSTEM" : "AUDIT_EXPORT_PROJECT", {
    targetId: study.currentStudy?.id,
    targetName: study.currentStudy?.name,
    severity: "normal",
  });
};

onMounted(async () => {
  if (!auth.user && auth.token) {
    await auth.fetchMe().catch(() => {});
  }
  ensureAccess();
  await loadUsers();
  await loadLogs();
});
</script>

<style scoped>
.page {
  display: flex;
  flex-direction: column;
}

.table-section {
  padding-top: 12px;
  padding-bottom: 12px;
}

.filter-form {
  display: flex;
  width: 100%;
  gap: 12px;
  align-items: center;
}

.filter-item-form {
  margin-bottom: 0 !important;
  margin-right: 0 !important;
}

.filter-select-comp {
  width: 150px;
}

.date-range-picker-comp {
  width: 280px !important;
}

.filter-spacer {
  flex: 1;
}

.diff-container {
  font-size: 13px;
  color: #4b5563;
  line-height: 1.5;
}

.diff-line {
  margin-bottom: 2px;
  word-break: break-all;
}

.pagination {
  margin-top: 12px;
  display: flex;
  justify-content: flex-end;
}
</style>
