<script setup lang="ts">
import { ref, onMounted } from "vue";
import { apiGet, apiPost, apiPut, apiDelete } from "@/api/client";
import { useAuthStore } from "@/stores/auth";
import { useToastStore } from "@/stores/toast";
import type { User } from "@/types/auth";

interface Invitation {
  id: number;
  email: string;
  created_at: string;
  expires_at: string;
}

const authStore = useAuthStore();
const toastStore = useToastStore();

const users = ref<User[]>([]);
const registrationOpen = ref(false);
const loading = ref(true);
const toggling = ref(false);
const confirmDeleteId = ref<number | null>(null);
const deleting = ref<number | null>(null);

const inviteEmail = ref("");
const sendingInvite = ref(false);
const invitations = ref<Invitation[]>([]);
const revokingId = ref<number | null>(null);

onMounted(async () => {
  await Promise.all([fetchUsers(), fetchRegistration(), fetchInvitations()]);
  loading.value = false;
});

async function fetchUsers() {
  try {
    const data = await apiGet<{ users: User[] }>("/api/admin/users");
    users.value = data.users;
  } catch {
    toastStore.show("Failed to load users", "error");
  }
}

async function fetchRegistration() {
  try {
    const data = await apiGet<{ open: boolean }>("/api/admin/registration");
    registrationOpen.value = data.open;
  } catch {
    // Ignore — will default to false
  }
}

async function fetchInvitations() {
  try {
    const data = await apiGet<{ invitations: Invitation[] }>("/api/admin/invitations");
    invitations.value = data.invitations;
  } catch {
    // Ignore
  }
}

async function sendInvite() {
  const email = inviteEmail.value.trim().toLowerCase();
  if (!email) return;
  sendingInvite.value = true;
  try {
    await apiPost("/api/admin/invitations", { email });
    toastStore.show(`Invitation sent to ${email}`);
    inviteEmail.value = "";
    await fetchInvitations();
  } catch (e: unknown) {
    if (e && typeof e === "object" && "body" in e) {
      const body = (e as { body?: { error?: string } }).body;
      toastStore.show(body?.error || "Failed to send invitation", "error");
    } else {
      toastStore.show("Failed to send invitation", "error");
    }
  } finally {
    sendingInvite.value = false;
  }
}

async function revokeInvitation(id: number) {
  revokingId.value = id;
  try {
    await apiDelete(`/api/admin/invitations/${id}`);
    invitations.value = invitations.value.filter((inv) => inv.id !== id);
    toastStore.show("Invitation revoked");
  } catch {
    toastStore.show("Failed to revoke invitation", "error");
  } finally {
    revokingId.value = null;
  }
}

async function toggleRegistration() {
  toggling.value = true;
  try {
    const data = await apiPut<{ open: boolean }>("/api/admin/registration", {
      open: !registrationOpen.value,
    });
    registrationOpen.value = data.open;
    toastStore.show(data.open ? "Registration opened" : "Registration closed");
  } catch {
    toastStore.show("Failed to update registration setting", "error");
  } finally {
    toggling.value = false;
  }
}

function confirmDelete(userId: number) {
  if (confirmDeleteId.value === userId) {
    deleteUser(userId);
  } else {
    confirmDeleteId.value = userId;
  }
}

function cancelDelete() {
  confirmDeleteId.value = null;
}

async function deleteUser(userId: number) {
  confirmDeleteId.value = null;
  deleting.value = userId;
  try {
    await apiDelete(`/api/admin/users/${userId}`);
    users.value = users.value.filter((u) => u.id !== userId);
    toastStore.show("User deleted");
  } catch (e: unknown) {
    if (e && typeof e === "object" && "body" in e) {
      const body = (e as { body?: { error?: string } }).body;
      toastStore.show(body?.error || "Failed to delete user", "error");
    } else {
      toastStore.show("Failed to delete user", "error");
    }
  } finally {
    deleting.value = null;
  }
}

function formatDate(iso: string): string {
  return new Date(iso).toLocaleDateString(undefined, {
    year: "numeric",
    month: "short",
    day: "numeric",
  });
}
</script>

<template>
  <main class="users-page">
    <h1>User Management</h1>

    <section class="settings-section">
      <h2>Registration</h2>
      <div class="registration-row">
        <div class="registration-info">
          <p class="registration-status">
            Registration is currently
            <strong :class="registrationOpen ? 'text-success' : 'text-muted'">
              {{ registrationOpen ? "open" : "closed" }}
            </strong>
          </p>
          <p class="field-hint">
            When closed, new users can only be added by an administrator.
          </p>
        </div>
        <button
          class="btn-toggle"
          :class="registrationOpen ? 'btn-toggle-close' : 'btn-toggle-open'"
          @click="toggleRegistration"
          :disabled="toggling"
        >
          {{ toggling ? "Updating..." : registrationOpen ? "Close Registration" : "Open Registration" }}
        </button>
      </div>
    </section>

    <section class="settings-section">
      <h2>Invite User</h2>
      <form class="invite-form" @submit.prevent="sendInvite">
        <input
          v-model="inviteEmail"
          type="email"
          placeholder="Email address"
          class="input invite-input"
          required
          :disabled="sendingInvite"
        />
        <button
          type="submit"
          class="btn-invite"
          :disabled="sendingInvite || !inviteEmail.trim()"
        >
          {{ sendingInvite ? "Sending..." : "Send Invite" }}
        </button>
      </form>
      <p class="field-hint">Send an invitation link to allow someone to register, even when public registration is closed.</p>

      <div v-if="invitations.length > 0" class="invite-list">
        <h3>Pending Invitations</h3>
        <table class="users-table">
          <thead>
            <tr>
              <th>Email</th>
              <th class="hide-mobile">Sent</th>
              <th class="hide-mobile">Expires</th>
              <th>Actions</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="inv in invitations" :key="inv.id">
              <td class="cell-email">{{ inv.email }}</td>
              <td class="hide-mobile cell-date">{{ formatDate(inv.created_at) }}</td>
              <td class="hide-mobile cell-date">{{ formatDate(inv.expires_at) }}</td>
              <td class="cell-actions">
                <button
                  class="btn-delete"
                  @click="revokeInvitation(inv.id)"
                  :disabled="revokingId !== null"
                >
                  {{ revokingId === inv.id ? "Revoking..." : "Revoke" }}
                </button>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
    </section>

    <section class="settings-section">
      <h2>Users</h2>

      <div v-if="loading" class="loading-msg">Loading users...</div>

      <div v-else-if="users.length === 0" class="empty-msg">No users found.</div>

      <table v-else class="users-table">
        <thead>
          <tr>
            <th>Username</th>
            <th class="hide-mobile">Email</th>
            <th>Role</th>
            <th class="hide-mobile">Joined</th>
            <th>Actions</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="u in users" :key="u.id">
            <td class="cell-username">{{ u.username }}</td>
            <td class="hide-mobile cell-email">{{ u.email || "—" }}</td>
            <td>
              <span class="role-badge" :class="u.role === 'admin' ? 'role-admin' : 'role-user'">
                {{ u.role }}
              </span>
            </td>
            <td class="hide-mobile cell-date">{{ formatDate(u.created_at) }}</td>
            <td class="cell-actions">
              <template v-if="u.id === authStore.user?.id">
                <span class="you-label">You</span>
              </template>
              <template v-else-if="confirmDeleteId === u.id">
                <button
                  class="btn-confirm-delete"
                  @click="confirmDelete(u.id)"
                  :disabled="deleting !== null"
                >
                  {{ deleting === u.id ? "Deleting..." : "Confirm" }}
                </button>
                <button class="btn-cancel-delete" @click="cancelDelete">Cancel</button>
              </template>
              <template v-else>
                <button
                  class="btn-delete"
                  @click="confirmDelete(u.id)"
                  :disabled="deleting !== null"
                >
                  Delete
                </button>
              </template>
            </td>
          </tr>
        </tbody>
      </table>
    </section>
  </main>
</template>

<style scoped>
.users-page {
  max-width: 1200px;
  margin: 2rem auto;
  padding: 0 1rem;
}
.users-page h1 {
  margin: 0 0 1.5rem;
}
.settings-section {
  background: var(--color-bg-card);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: 1.25rem;
  margin-bottom: 1.5rem;
}
.settings-section h2 {
  margin: 0 0 0.75rem;
  font-size: 1.1rem;
}

/* Invite form */
.invite-form {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
}
.invite-input {
  flex: 1;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-size: 0.95rem;
  background: var(--color-bg);
  color: var(--color-text);
  box-sizing: border-box;
}
.invite-input:focus {
  outline: none;
  border-color: var(--color-primary);
}
.btn-invite {
  padding: 0.45rem 1rem;
  background: var(--color-primary);
  color: #fff;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 0.9rem;
  font-weight: 600;
  white-space: nowrap;
}
.btn-invite:disabled {
  opacity: 0.6;
  cursor: default;
}
.btn-invite:hover:not(:disabled) {
  opacity: 0.9;
}
.invite-list {
  margin-top: 1rem;
}
.invite-list h3 {
  margin: 0 0 0.5rem;
  font-size: 0.95rem;
  color: var(--color-text-secondary);
}

/* Registration toggle */
.registration-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}
.registration-info {
  flex: 1;
}
.registration-status {
  margin: 0;
  font-size: 0.95rem;
}
.text-success {
  color: var(--color-success);
}
.text-muted {
  color: var(--color-text-muted);
}
.field-hint {
  margin: 0.35rem 0 0;
  font-size: 0.8rem;
  color: var(--color-text-muted);
}
.btn-toggle {
  padding: 0.45rem 1rem;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 0.9rem;
  font-weight: 600;
  white-space: nowrap;
}
.btn-toggle:disabled {
  opacity: 0.6;
  cursor: default;
}
.btn-toggle-open {
  background: var(--color-primary);
  color: #fff;
}
.btn-toggle-open:hover:not(:disabled) {
  opacity: 0.9;
}
.btn-toggle-close {
  background: var(--color-bg-secondary);
  color: var(--color-text);
  border: 1px solid var(--color-border);
}
.btn-toggle-close:hover:not(:disabled) {
  border-color: var(--color-warning);
  color: var(--color-warning);
}

/* Users table */
.loading-msg,
.empty-msg {
  text-align: center;
  color: var(--color-text-muted);
  font-size: 0.9rem;
  padding: 1rem 0;
}
.users-table {
  width: 100%;
  border-collapse: collapse;
}
.users-table th {
  text-align: left;
  font-size: 0.8rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-muted);
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--color-border);
}
.users-table td {
  padding: 0.65rem 0.75rem;
  border-bottom: 1px solid var(--color-border);
  font-size: 0.9rem;
}
.users-table tbody tr:last-child td {
  border-bottom: none;
}
.cell-username {
  font-weight: 600;
}
.cell-email {
  color: var(--color-text-secondary);
}
.cell-date {
  color: var(--color-text-muted);
  font-size: 0.85rem;
}
.cell-actions {
  white-space: nowrap;
}

/* Role badges */
.role-badge {
  display: inline-block;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 0.15rem 0.4rem;
  border-radius: var(--radius-sm);
}
.role-admin {
  color: var(--color-primary);
  background: color-mix(in srgb, var(--color-primary) 15%, transparent);
}
.role-user {
  color: var(--color-text-muted);
  background: var(--color-bg-secondary);
}

/* Action buttons */
.you-label {
  font-size: 0.8rem;
  color: var(--color-text-muted);
  font-style: italic;
}
.btn-delete {
  padding: 0.25rem 0.6rem;
  background: transparent;
  color: var(--color-text-muted);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 0.8rem;
}
.btn-delete:hover:not(:disabled) {
  border-color: var(--color-danger);
  color: var(--color-danger);
}
.btn-delete:disabled {
  opacity: 0.4;
  cursor: default;
}
.btn-confirm-delete {
  padding: 0.25rem 0.6rem;
  background: var(--color-danger);
  color: #fff;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 0.8rem;
  font-weight: 600;
  margin-right: 0.25rem;
}
.btn-confirm-delete:hover:not(:disabled) {
  filter: brightness(0.9);
}
.btn-confirm-delete:disabled {
  opacity: 0.6;
  cursor: default;
}
.btn-cancel-delete {
  padding: 0.25rem 0.6rem;
  background: transparent;
  color: var(--color-text-muted);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: 0.8rem;
}
.btn-cancel-delete:hover {
  color: var(--color-text);
  border-color: var(--color-text-muted);
}

@media (max-width: 768px) {
  .registration-row {
    flex-direction: column;
    align-items: flex-start;
  }
  .btn-toggle {
    width: 100%;
  }
  .invite-form {
    flex-direction: column;
  }
}
</style>
