<script setup>
// User management, shown as the Users tab of Settings (admins + superadmins).
// Admins see their own organization; superadmins see every account.
import { ref, computed, onMounted } from "vue";
import { api } from "../api";
import { state } from "../auth";
import { formatDate } from "../lib/format.js";
import { t } from "../i18n";
import { askConfirm } from "../lib/confirm.js";
import Modal from "./Modal.vue";

const users = ref([]);
const loading = ref(true);
const error = ref("");

// Create-user modal.
const showCreate = ref(false);
const createForm = ref({ email: "", name: "", password: "", role: "user", organization: "" });
const creating = ref(false);
const createError = ref("");

// Organizations a superadmin can drop the new account into. Admins get no
// picker: the server puts their members in their own org regardless.
const orgs = ref([]);

// Reset-password modal.
const pwUser = ref(null);
const newPassword = ref("");
const savingPw = ref(false);
const pwError = ref("");

const myId = state.user?.id;
const myRole = computed(() => state.profile?.role || state.user?.role || "user");
const isSuperadmin = computed(() => myRole.value === "superadmin");

// Roles this viewer may hand out. Only a superadmin can mint another one; the
// server rejects it either way, this just doesn't offer a doomed option.
const assignableRoles = computed(() =>
  isSuperadmin.value ? ["user", "admin", "superadmin"] : ["user", "admin"],
);

// Whether the destructive/role controls should be disabled for a row, with a
// reason. These mirror the server's guards so the UI doesn't offer an action
// that is going to come back as a 400/403.
function deleteBlockedReason(u) {
  if (u.id === myId) return t("admin.cantDeleteSelf");
  if (u.role === "superadmin" && !isSuperadmin.value) return t("admin.onlySuperadminDeletes");
  return "";
}
function roleLockReason(u) {
  if (u.id === myId) return t("admin.cantChangeOwnRole");
  if (u.role === "superadmin" && !isSuperadmin.value) return t("admin.onlySuperadminEdits");
  return "";
}

async function load() {
  loading.value = true;
  error.value = "";
  try {
    users.value = await api.listUsers();
  } catch (e) {
    error.value = e.message;
  } finally {
    loading.value = false;
  }
}

async function changeRole(u, role) {
  if (role === u.role) return;
  error.value = "";
  try {
    const updated = await api.updateUser(u.id, { role });
    Object.assign(u, updated);
  } catch (e) {
    error.value = e.message;
    await load(); // resync the select back to the true value
  }
}

async function submitCreate() {
  creating.value = true;
  createError.value = "";
  try {
    const body = {
      email: createForm.value.email.trim(),
      name: createForm.value.name.trim(),
      password: createForm.value.password,
      role: createForm.value.role,
    };
    // Only a superadmin picks the organization — an empty pick deliberately
    // creates an org-less account. For an admin the server forces its own org,
    // so sending anything here would be noise.
    if (isSuperadmin.value) body.organization = createForm.value.organization;
    await api.createUser(body);
    showCreate.value = false;
    createForm.value = { email: "", name: "", password: "", role: "user", organization: "" };
    await load();
  } catch (e) {
    createError.value = e.message;
  } finally {
    creating.value = false;
  }
}

function openResetPassword(u) {
  pwUser.value = u;
  newPassword.value = "";
  pwError.value = "";
}

async function submitResetPassword() {
  savingPw.value = true;
  pwError.value = "";
  try {
    await api.setUserPassword(pwUser.value.id, newPassword.value);
    pwUser.value = null;
  } catch (e) {
    pwError.value = e.message;
  } finally {
    savingPw.value = false;
  }
}

async function removeUser(u) {
  if (!(await askConfirm(t("admin.confirmDelete", { name: u.name || u.email })))) return;
  error.value = "";
  try {
    await api.deleteUser(u.id);
    await load();
  } catch (e) {
    error.value = e.message;
  }
}

onMounted(async () => {
  await load();
  // Listing orgs is manager-only and an admin only ever gets their own back, so
  // fetch it just for the superadmin picker. A failure leaves the picker empty
  // rather than breaking the table.
  if (isSuperadmin.value) {
    try {
      orgs.value = (await api.listOrgs()) || [];
    } catch {
      orgs.value = [];
    }
  }
});
</script>

<template>
  <div>
    <div class="mb-4 flex items-center justify-between gap-3">
      <div>
        <h2 class="text-lg font-bold tracking-[-0.02em] text-strong">{{ t("admin.title") }}</h2>
        <p class="mt-0.5 text-xs text-muted">
          {{ isSuperadmin ? t("admin.subtitleAll") : t("admin.subtitleOrg") }}
        </p>
      </div>
      <button class="dh-btn dh-btn-primary shrink-0" @click="showCreate = true">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" class="h-4 w-4"><path stroke-linecap="round" stroke-linejoin="round" d="M12 5v14M5 12h14" /></svg>
        {{ t("admin.addUser") }}
      </button>
    </div>

    <p v-if="error" class="mb-4 rounded-control bg-danger-soft px-4 py-3 text-sm font-medium text-danger">{{ error }}</p>
    <p v-if="loading" class="text-muted">{{ t("common.loading") }}</p>

    <div v-else class="dh-card overflow-x-auto p-0">
      <table class="min-w-full text-sm">
        <thead class="bg-sunken text-left">
          <tr class="[&>th]:eyebrow [&>th]:px-4 [&>th]:py-3">
            <th>{{ t("admin.colEmail") }}</th>
            <th>{{ t("admin.colName") }}</th>
            <th>{{ t("admin.colOrganization") }}</th>
            <th>{{ t("admin.colRole") }}</th>
            <th>{{ t("admin.colCreated") }}</th>
            <th></th>
          </tr>
        </thead>
        <tbody class="divide-y divide-subtle">
          <tr v-for="u in users" :key="u.id" class="transition-colors hover:bg-sunken">
            <td class="px-4 py-3 font-medium text-strong">
              {{ u.email }}
              <span v-if="u.id === myId" class="ml-1 text-xs text-muted">{{ t("admin.you") }}</span>
            </td>
            <td class="px-4 py-3 text-body">{{ u.name || t("common.empty") }}</td>
            <td class="px-4 py-3 text-body">{{ u.organizationName || t("common.empty") }}</td>
            <td class="px-4 py-3">
              <select
                :value="u.role"
                :disabled="!!roleLockReason(u)"
                :title="roleLockReason(u)"
                class="dh-input w-auto !py-1 !text-xs disabled:opacity-60"
                @change="changeRole(u, $event.target.value)"
              >
                <option v-for="r in assignableRoles" :key="r" :value="r">{{ t(`admin.roles.${r}`) }}</option>
                <!-- Keep the current role selectable even when this viewer can't assign it. -->
                <option v-if="!assignableRoles.includes(u.role)" :value="u.role">{{ t(`admin.roles.${u.role}`) }}</option>
              </select>
            </td>
            <td class="px-4 py-3 data text-muted">{{ formatDate(u.created) }}</td>
            <td class="whitespace-nowrap px-4 py-3 text-right">
              <button class="text-xs font-medium text-brandtext hover:underline" @click="openResetPassword(u)">{{ t("admin.resetPassword") }}</button>
              <button
                class="ml-3 text-xs font-medium text-danger hover:underline disabled:cursor-not-allowed disabled:text-muted disabled:no-underline"
                :disabled="!!deleteBlockedReason(u)"
                :title="deleteBlockedReason(u)"
                @click="removeUser(u)"
              >
                {{ t("common.delete") }}
              </button>
            </td>
          </tr>
        </tbody>
      </table>
    </div>

    <!-- Create user -->
    <Modal v-if="showCreate" :title="t('admin.createTitle')" @close="showCreate = false">
      <p v-if="createError" class="mb-3 rounded-control bg-danger-soft px-3 py-2 text-sm font-medium text-danger">{{ createError }}</p>
      <form class="space-y-3" @submit.prevent="submitCreate">
        <div>
          <label class="dh-label">{{ t("admin.emailRequired") }}</label>
          <input v-model="createForm.email" type="email" required autocomplete="off" class="dh-input" />
        </div>
        <div>
          <label class="dh-label">{{ t("admin.colName") }}</label>
          <input v-model="createForm.name" autocomplete="off" class="dh-input" />
        </div>
        <div class="grid grid-cols-2 gap-2">
          <div>
            <label class="dh-label">{{ t("admin.passwordRequired") }} <span class="text-muted">{{ t("admin.minChars") }}</span></label>
            <input v-model="createForm.password" type="text" required minlength="8" autocomplete="new-password" class="dh-input data" />
          </div>
          <div>
            <label class="dh-label">{{ t("admin.colRole") }}</label>
            <select v-model="createForm.role" class="dh-input">
              <option v-for="r in assignableRoles" :key="r" :value="r">{{ t(`admin.roles.${r}`) }}</option>
            </select>
          </div>
        </div>
        <!-- Superadmins choose the organization (or leave the account org-less);
             an admin's members always land in the admin's own organization. -->
        <div v-if="isSuperadmin">
          <label class="dh-label">{{ t("admin.colOrganization") }}</label>
          <select v-model="createForm.organization" class="dh-input">
            <option value="">{{ t("admin.noOrganization") }}</option>
            <option v-for="o in orgs" :key="o.id" :value="o.id">{{ o.name }}</option>
          </select>
          <p class="mt-1 text-xs text-muted">{{ t("admin.organizationHint") }}</p>
        </div>
        <div class="mt-4 flex justify-end gap-2">
          <button type="button" class="dh-btn dh-btn-ghost" @click="showCreate = false">{{ t("common.cancel") }}</button>
          <button type="submit" :disabled="creating" class="dh-btn dh-btn-primary">
            {{ creating ? t("admin.creating") : t("admin.createUser") }}
          </button>
        </div>
      </form>
    </Modal>

    <!-- Reset password -->
    <Modal v-if="pwUser" :title="t('admin.resetTitle', { email: pwUser.email })" @close="pwUser = null">
      <p v-if="pwError" class="mb-3 rounded-control bg-danger-soft px-3 py-2 text-sm font-medium text-danger">{{ pwError }}</p>
      <form class="space-y-3" @submit.prevent="submitResetPassword">
        <div>
          <label class="dh-label">{{ t("admin.newPassword") }} <span class="text-muted">{{ t("admin.minChars") }}</span></label>
          <input v-model="newPassword" type="text" required minlength="8" autocomplete="new-password" class="dh-input data" />
        </div>
        <div class="mt-4 flex justify-end gap-2">
          <button type="button" class="dh-btn dh-btn-ghost" @click="pwUser = null">{{ t("common.cancel") }}</button>
          <button type="submit" :disabled="savingPw" class="dh-btn dh-btn-primary">
            {{ savingPw ? t("common.saving") : t("admin.setPassword") }}
          </button>
        </div>
      </form>
    </Modal>
  </div>
</template>
