<template>
  <div class="page">
    <div class="main-content-flat unified-shell">
      <div class="unified-action-bar actions-only-bar">
        <div class="filter-spacer"></div>
        <el-button v-if="canAddMember" type="primary" @click="openAdd">
          {{ TEXT.common.actions.add }}{{ TEXT.modules.adminProjectMembers.memberLabel }}
        </el-button>
      </div>
      <div class="unified-section member-table-section">
        <el-table :data="memberRows" v-loading="loading" stripe class="member-table">
          <el-table-column prop="full_name" :label="TEXT.modules.adminProjectMembers.username" min-width="160" />
          <el-table-column prop="role_in_study" :label="TEXT.modules.adminProjectMembers.projectRole" min-width="140">
            <template #default="scope">
              <el-tag>{{ roleLabel(scope.row.role_in_study) }}</el-tag>
            </template>
          </el-table-column>
          <el-table-column :label="TEXT.common.fields.status" width="100">
            <template #default="scope">
              <el-tooltip
                v-if="scope.row.effectiveStatus === 'DISABLED_GLOBAL'"
                :content="TEXT.modules.adminProjectMembers.disabledGlobalHint"
                placement="top"
              >
                <el-tag type="danger">{{ TEXT.modules.adminProjectMembers.disabledGlobal }}</el-tag>
              </el-tooltip>
              <el-tag v-else :type="scope.row.is_active ? 'success' : 'danger'">
                {{ scope.row.is_active ? TEXT.common.actions.enable : TEXT.modules.adminProjectMembers.disabled }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="added_at" :label="TEXT.modules.adminProjectMembers.addedAt" min-width="180">
            <template #default="scope">{{ displayDateTime(scope.row.added_at) }}</template>
          </el-table-column>
          <el-table-column :label="TEXT.common.labels.actions" width="300" align="center" class-name="action-column">
            <template #default="scope">
              <el-select
                v-model="scope.row.role_in_study"
                size="small"
                style="width: 120px"
                @change="(val: string) => updateRole(scope.row.id, val)"
                :disabled="!canEditMember(scope.row) || !scope.row.is_active || scope.row.effectiveStatus === 'DISABLED_GLOBAL'"
              >
                <el-option
                  v-for="role in roleOptions"
                  :key="role.value"
                  :label="role.label"
                  :value="role.value"
                  :disabled="!canAssignRole(role.value)"
                />
              </el-select>
              <span v-if="scope.row.effectiveStatus === 'DISABLED_GLOBAL'" class="hint">{{ TEXT.modules.adminProjectMembers.disabledGlobalDesc }}</span>
              <el-button link type="danger" size="small" :disabled="!canDeleteProjectMember(scope.row)" @click="onDelete(scope.row)">{{ TEXT.common.actions.delete }}</el-button>
              <el-button
                link
                :type="scope.row.is_active ? 'danger' : 'primary'"
                size="small"
                :disabled="!canEditMember(scope.row) || scope.row.effectiveStatus === 'DISABLED_GLOBAL'"
                @click="toggleActive(scope.row)"
              >
                {{ scope.row.is_active ? TEXT.common.actions.disable : TEXT.common.actions.enable }}
              </el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>
    </div>

    <el-dialog v-if="addVisible" append-to=".layout-main .content-wrapper" :title="TEXT.modules.adminProjectMembers.newTitle" width="520px" v-model="addVisible" :close-on-click-modal="false">
      <el-form :model="newMember" label-width="120px" ref="addFormRef" :rules="addRules">
        <el-form-item :label="TEXT.modules.adminProjectMembers.user" prop="user_id">
          <el-select v-model="newMember.user_id" filterable :placeholder="TEXT.modules.adminProjectMembers.userPlaceholder">
            <el-option
              v-for="user in availableUsers"
              :key="user.id"
              :label="user.full_name || TEXT.common.fallback"
              :value="user.id"
              :disabled="!user.is_active"
            />
          </el-select>
        </el-form-item>
        <el-form-item :label="TEXT.modules.adminProjectMembers.projectRole" prop="role_in_study">
          <el-select v-model="newMember.role_in_study" :placeholder="TEXT.modules.adminProjectMembers.rolePlaceholder">
            <el-option
              v-for="role in roleOptions"
              :key="role.value"
              :label="role.label"
              :value="role.value"
              :disabled="!canAssignRole(role.value)"
            />
          </el-select>
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="addVisible = false">{{ TEXT.common.actions.cancel }}</el-button>
        <el-button type="primary" :loading="adding" @click="submitAdd">{{ TEXT.common.actions.save }}</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { computed, onMounted, reactive, ref } from "vue";
import { useRoute } from "vue-router";
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from "element-plus";
import { addMember, listMemberCandidates, listMembers, removeMember, updateMember } from "../../api/members";
import { fetchStudyDetail } from "../../api/studies";
import type { Study, StudyMember, UserInfo } from "../../types/api";
import { useAuthStore } from "../../store/auth";
import { evaluateAction } from "../../guards/actionGuard";
import { usePermission } from "../../utils/permission";
import { displayDateTime } from "../../utils/display";
import { TEXT, requiredMessage } from "../../locales";
import { useRoleTemplateMeta } from "../../composables/useRoleTemplateMeta";

const route = useRoute();
const projectId = computed(() => route.params.projectId as string);
const auth = useAuthStore();
const permission = usePermission();
const { roleLabel, roleOptionsFor, loadRoleTemplates } = useRoleTemplateMeta();

const project = ref<Study | null>(null);
const members = ref<StudyMember[]>([]);
const users = ref<UserInfo[]>([]);
const loading = ref(false);
const addVisible = ref(false);
const adding = ref(false);
const addFormRef = ref<FormInstance>();
const newMember = reactive({
  user_id: "",
  role_in_study: "PM",
});
const canListMembers = computed(() => permission.can("project.members.list"));
const canListMemberCandidates = computed(() => permission.can("project.members.candidates"));
const canCreateMember = computed(() => permission.can("project.members.create"));
const canUpdateMember = computed(() => permission.can("project.members.update"));
const canDeleteMember = computed(() => permission.can("project.members.delete"));
const canAddMember = computed(() => canCreateMember.value && canListMemberCandidates.value);
const projectRole = computed(() => project.value?.role_in_study || "");
const ROLE_KEYS = ["PM", "CRA", "PV", "QA", "CTA", "ADMIN"];
const roleOptions = computed(() => roleOptionsFor(ROLE_KEYS));
const roleRank: Record<string, number> = {
  ADMIN: 100,
  PM: 80,
  PV: 50,
  QA: 60,
  CRA: 40,
  CTA: 40,
};
const currentRoleRank = computed(() => auth.user?.is_admin ? Number.POSITIVE_INFINITY : roleRank[projectRole.value] || 0);
const canAssignRole = (role: string) => (auth.user?.is_admin ? true : (roleRank[role] || 0) <= currentRoleRank.value);
const canMutateProjectMember = (row: StudyMember) => {
  if (row.user?.is_admin) return false;
  if (auth.user?.is_admin) return true;
  if (row.user_id === auth.user?.id) return false;
  return (roleRank[row.role_in_study] || 0) <= currentRoleRank.value;
};
const canEditMember = (row: StudyMember) => canUpdateMember.value && canMutateProjectMember(row);
const canDeleteProjectMember = (row: StudyMember) => canDeleteMember.value && canMutateProjectMember(row);

const addRules = reactive<FormRules>({
  user_id: [{ required: true, message: requiredMessage(TEXT.modules.adminProjectMembers.user), trigger: "change" }],
  role_in_study: [{ required: true, message: requiredMessage(TEXT.modules.adminProjectMembers.projectRole), trigger: "change" }],
});

const loadProject = async () => {
  if (!projectId.value) return;
  try {
    const { data } = await fetchStudyDetail(projectId.value);
    project.value = data;
  } catch {
    /* ignore */
  }
};

const loadMembers = async () => {
  if (!canListMembers.value || !projectId.value) return;
  loading.value = true;
  try {
    const { data } = await listMembers(projectId.value, { limit: 500, include_inactive: true });
    members.value = Array.isArray(data) ? data : data.items || [];
    if (!canListMemberCandidates.value) syncUsersFromMembers();
  } catch (e: any) {
    ElMessage.error(e?.response?.data?.message || TEXT.modules.adminProjectMembers.loadFailed);
  } finally {
    loading.value = false;
  }
};

const syncUsersFromMembers = () => {
  users.value = members.value
    .map((member) => member.user)
    .filter((user): user is UserInfo => Boolean(user?.id)) as UserInfo[];
};

const loadUsers = async () => {
  if (!canListMemberCandidates.value || !projectId.value) {
    syncUsersFromMembers();
    return;
  }
  try {
    const { data } = await listMemberCandidates(projectId.value, { limit: 500 });
    users.value = data || [];
  } catch {
    users.value = [];
  }
};

const memberRows = computed(() =>
  members.value.map((m) => {
    const user = users.value.find((u) => u.id === m.user_id) || m.user;
    const effectiveStatus = user && user.is_active === false ? "DISABLED_GLOBAL" : m.is_active ? "ACTIVE" : "DISABLED";
    return {
      ...m,
      full_name: user?.full_name || user?.username || m.user_id,
      effectiveStatus,
    };
  })
);

const openAdd = () => {
  if (!canAddMember.value) return;
  newMember.user_id = "";
  newMember.role_in_study = canAssignRole("PM") ? "PM" : "CRA";
  addVisible.value = true;
};

const submitAdd = async () => {
  if (!projectId.value) return;
  if (!canAddMember.value) {
    ElMessage.warning(TEXT.common.messages.noPermission);
    return;
  }
  const decision = evaluateAction({
    actorRole: auth.user?.is_admin ? "ADMIN" : null,
    requiredPermission: "project.members.create",
    target: { projectId: projectId.value },
  });
  if (!decision.allowed) {
    ElMessage.warning(decision.reason || TEXT.common.messages.noPermission);
    return;
  }
  if (!canAssignRole(newMember.role_in_study)) {
    ElMessage.warning(TEXT.common.messages.noPermission);
    return;
  }
  await addFormRef.value?.validate();
  adding.value = true;
  try {
    await addMember(projectId.value, newMember);
    ElMessage.success(TEXT.modules.adminProjectMembers.addSuccess);
    addVisible.value = false;
    await Promise.all([loadMembers(), loadUsers()]);
  } catch (e: any) {
    ElMessage.error(e?.response?.data?.message || TEXT.modules.adminProjectMembers.addFailed);
  } finally {
    adding.value = false;
  }
};

const updateRole = async (memberId: string, role: string) => {
  if (!projectId.value) return;
  const row = members.value.find((member) => member.id === memberId);
  if (!row || !canEditMember(row) || !canAssignRole(role)) {
    ElMessage.warning(TEXT.common.messages.noPermission);
    loadMembers();
    return;
  }
  const decision = evaluateAction({
    actorRole: auth.user?.is_admin ? "ADMIN" : null,
    requiredPermission: "project.members.update",
    target: { projectId: projectId.value, memberId },
  });
  if (!decision.allowed) {
    ElMessage.warning(decision.reason || TEXT.common.messages.noPermission);
    return;
  }
  try {
    await updateMember(projectId.value, memberId, { role_in_study: role });
    ElMessage.success(TEXT.modules.adminProjectMembers.roleUpdated);
    loadMembers();
  } catch (e: any) {
    ElMessage.error(e?.response?.data?.message || TEXT.common.messages.updateFailed);
    loadMembers();
  }
};

const toggleActive = async (row: StudyMember) => {
  if (!projectId.value) return;
  if (!canEditMember(row)) {
    ElMessage.warning(TEXT.common.messages.noPermission);
    return;
  }
  const decision = evaluateAction({
    actorRole: auth.user?.is_admin ? "ADMIN" : null,
    requiredPermission: "project.members.update",
    target: { projectId: projectId.value, memberId: row.id },
  });
  if (!decision.allowed) {
    ElMessage.warning(decision.reason || TEXT.common.messages.noPermission);
    return;
  }
  if (row.is_active) {
    const ok = await ElMessageBox.confirm(TEXT.modules.adminProjectMembers.disableConfirm, TEXT.modules.adminProjectMembers.disableTitle, {
      type: "warning",
      confirmButtonText: TEXT.common.actions.confirm,
    }).catch(() => null);
    if (!ok) return;
    try {
      await updateMember(projectId.value, row.id, { is_active: false });
      ElMessage.success(TEXT.modules.adminProjectMembers.disableSuccess);
      loadMembers();
    } catch (e: any) {
      ElMessage.error(e?.response?.data?.message || TEXT.common.messages.actionFailed);
    }
  } else {
    try {
      await updateMember(projectId.value, row.id, { is_active: true });
      ElMessage.success(TEXT.modules.adminProjectMembers.enableSuccess);
      loadMembers();
    } catch (e: any) {
      ElMessage.error(e?.response?.data?.message || TEXT.common.messages.actionFailed);
    }
  }
};

const onDelete = async (row: StudyMember) => {
  if (!projectId.value) return;
  if (!canDeleteProjectMember(row)) {
    ElMessage.warning(TEXT.common.messages.noPermission);
    return;
  }
  const decision = evaluateAction({
    actorRole: auth.user?.is_admin ? "ADMIN" : null,
    requiredPermission: "project.members.delete",
    target: { projectId: projectId.value, memberId: row.id },
  });
  if (!decision.allowed) {
    ElMessage.warning(decision.reason || TEXT.common.messages.noPermission);
    return;
  }
  const ok = await ElMessageBox.confirm(TEXT.modules.adminProjectMembers.removeConfirm, TEXT.modules.adminProjectMembers.removeTitle, {
    type: "warning",
    confirmButtonText: TEXT.common.actions.confirm,
    cancelButtonText: TEXT.common.actions.cancel,
  }).catch(() => null);
  if (!ok) return;
  try {
    await removeMember(projectId.value, row.id);
    members.value = members.value.filter((m) => m.id !== row.id);
    await loadUsers();
    ElMessage.success(TEXT.modules.adminProjectMembers.removeSuccess);
  } catch (e: any) {
    ElMessage.error(e?.response?.data?.message || TEXT.common.messages.deleteFailed);
  }
};

const availableUsers = computed(() => {
  const memberUserIds = new Set(members.value.map((m) => m.user_id));
  return users.value.filter((u) => !memberUserIds.has(u.id));
});

onMounted(async () => {
  await Promise.all([loadRoleTemplates(), loadProject(), loadMembers()]);
  loadUsers();
});
</script>

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

.main-content-flat {
  width: 100%;
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  padding: 0;
}

.main-content-flat :deep(.el-card__body) {
  padding: 0;
}

.actions-only-bar {
  display: flex;
  justify-content: flex-end;
  align-items: center;
}

.member-table-section {
  padding: 0;
}

.member-table :deep(.el-table__inner-wrapper::before) {
  display: none;
}

.hint {
  color: #999;
  margin: 0 8px;
  font-size: 12px;
}
</style>

<style>
.el-table .action-column .cell {
  padding-left: 8px;
  padding-right: 8px;
}

.action-column .el-select {
  margin-right: 8px;
}
</style>
