<template>
  <div>
    <div class="flex items-start justify-between mb-8">
      <div>
        <h1 class="text-xl font-semibold text-white mb-1">Moderation</h1>
        <p class="text-sm text-gray-500">
          Gemeldete Inhalte prüfen, dismiss / delete / ban-user. Audit-Log persistiert.
        </p>
      </div>
      <UButton
        color="neutral"
        variant="ghost"
        icon="heroicons:arrow-path"
        :loading="pending"
        size="sm"
        @click="reload()"
      >
        Aktualisieren
      </UButton>
    </div>

    <!-- Error-State -->
    <div
      v-if="error"
      class="rounded-lg border border-red-900 bg-red-950/40 p-4 mb-4 flex items-start gap-3"
    >
      <UIcon
        name="heroicons:exclamation-triangle"
        class="h-5 w-5 text-red-400 shrink-0 mt-0.5"
      />
      <div class="flex-1">
        <p class="text-sm font-medium text-red-300">
          Fehler beim Laden der Moderation-Queue
        </p>
        <p class="text-xs text-red-400/80 mt-1">
          {{ error.statusMessage || error.message || "Unbekannter Fehler" }}
        </p>
      </div>
    </div>

    <!-- Loading-State (initial) -->
    <div
      v-else-if="pending && items.length === 0"
      class="rounded-lg border border-gray-800 bg-gray-900 p-12 text-center"
    >
      <UIcon
        name="heroicons:arrow-path"
        class="h-6 w-6 text-gray-600 mx-auto mb-3 animate-spin"
      />
      <p class="text-sm text-gray-500">Lade Moderation-Queue…</p>
    </div>

    <!-- Empty-State -->
    <div
      v-else-if="items.length === 0"
      class="rounded-lg border border-dashed border-gray-700 bg-gray-900 p-12 text-center"
    >
      <UIcon
        name="heroicons:shield-check"
        class="h-8 w-8 text-emerald-600 mx-auto mb-3"
      />
      <p class="text-sm text-gray-300">Keine offene moderation-items</p>
      <p class="text-xs text-gray-500 mt-2">
        Alle gemeldeten Inhalte sind bearbeitet.
      </p>
    </div>

    <!-- Stack-Layout: ein Card pro Item -->
    <div v-else class="space-y-3">
      <div
        v-for="item in items"
        :key="`${item.type}:${item.id}`"
        class="rounded-lg border border-gray-800 bg-gray-900 p-5"
      >
        <!-- Header-Row: type-badge, user-info, reportedAt -->
        <div class="flex items-start justify-between gap-4 mb-3">
          <div class="flex items-center gap-3 flex-wrap">
            <UBadge
              :color="item.type === 'post' ? 'primary' : 'info'"
              variant="subtle"
              size="sm"
            >
              {{ item.type === "post" ? "Post" : "Comment" }}
            </UBadge>

            <UBadge
              v-if="item.isDeleted"
              color="error"
              variant="subtle"
              size="sm"
            >
              gelöscht
            </UBadge>

            <span class="text-xs text-gray-500">
              <UIcon
                name="heroicons:user-circle"
                class="h-3.5 w-3.5 inline -mt-0.5"
              />
              {{ item.author?.nickname || "—" }}
              <span class="text-gray-600 ml-1">
                ({{ shortId(item.userId) }})
              </span>
            </span>

            <UBadge
              v-if="item.author?.plan && item.author.plan !== 'free'"
              :color="item.author.plan === 'legend' ? 'warning' : 'success'"
              variant="subtle"
              size="xs"
            >
              {{ item.author.plan }}
            </UBadge>
          </div>

          <span class="text-xs text-gray-500 shrink-0">
            {{
              item.reportedAt
                ? `gemeldet ${formatDate(item.reportedAt)}`
                : `erstellt ${formatDate(item.createdAt)}`
            }}
          </span>
        </div>

        <!-- Content-Preview (max 200 chars) -->
        <div
          class="rounded border border-gray-800 bg-gray-950/60 px-4 py-3 mb-4"
        >
          <p
            v-if="item.isDeleted"
            class="text-sm italic text-gray-600"
          >
            [Inhalt bereits gelöscht — Original im Audit-Log]
          </p>
          <p v-else class="text-sm text-gray-200 whitespace-pre-wrap">
            {{ truncate(item.content, 200) }}
          </p>
          <p
            v-if="item.type === 'comment' && item.postId"
            class="text-xs text-gray-600 mt-2"
          >
            zum Post {{ shortId(item.postId) }}
          </p>
        </div>

        <!-- Action-Buttons -->
        <div class="flex items-center justify-end gap-2 flex-wrap">
          <UButton
            color="neutral"
            variant="ghost"
            size="xs"
            icon="heroicons:check"
            :loading="busy(item, 'dismiss')"
            :disabled="anyBusy"
            @click="onDismiss(item)"
          >
            Dismiss
          </UButton>
          <UButton
            color="error"
            variant="soft"
            size="xs"
            icon="heroicons:trash"
            :disabled="anyBusy || item.isDeleted"
            :loading="busy(item, 'delete')"
            @click="askDelete(item)"
          >
            Delete Content
          </UButton>
          <UButton
            color="error"
            variant="solid"
            size="xs"
            icon="heroicons:no-symbol"
            :disabled="anyBusy"
            :loading="busy(item, 'ban')"
            @click="askBan(item)"
          >
            Ban User
          </UButton>
        </div>
      </div>

      <!-- Pagination -->
      <div v-if="nextCursor" class="flex justify-center pt-4">
        <UButton
          color="neutral"
          variant="outline"
          size="sm"
          :loading="loadingMore"
          @click="loadMore"
        >
          Mehr laden
        </UButton>
      </div>
    </div>

    <!-- Delete-Confirm-Modal -->
    <UModal v-model:open="deleteOpen" title="Inhalt löschen">
      <template #body>
        <div class="space-y-4">
          <p class="text-sm text-gray-300">
            {{ deleteTarget?.type === "post" ? "Post" : "Kommentar" }}
            wirklich soft-löschen? Original-Inhalt bleibt im Audit-Log
            erhalten.
          </p>
          <UTextarea
            v-model="deleteReason"
            placeholder="Optionale Begründung (intern)…"
            :rows="3"
            class="w-full"
          />
        </div>
      </template>
      <template #footer>
        <div class="flex justify-end gap-2 w-full">
          <UButton
            color="neutral"
            variant="ghost"
            :disabled="anyBusy"
            @click="deleteOpen = false"
          >
            Abbrechen
          </UButton>
          <UButton color="error" :loading="anyBusy" @click="confirmDelete">
            Löschen
          </UButton>
        </div>
      </template>
    </UModal>

    <!-- Ban-User-Confirm-Modal -->
    <UModal v-model:open="banOpen" title="User bannen">
      <template #body>
        <div class="space-y-4">
          <div
            class="rounded border border-red-900 bg-red-950/40 px-4 py-3 flex items-start gap-3"
          >
            <UIcon
              name="heroicons:exclamation-triangle"
              class="h-5 w-5 text-red-400 shrink-0 mt-0.5"
            />
            <div class="text-xs text-red-300">
              User wird auf API-Ebene gesperrt (Login bleibt unberührt).
              Reuses /api/admin/users[id]-Patch-Pattern.
            </div>
          </div>
          <p class="text-sm text-gray-300">
            User
            <span class="font-mono text-white">{{
              banTarget?.author?.nickname || shortId(banTarget?.userId || "")
            }}</span>
            wegen
            {{ banTarget?.type === "post" ? "diesem Post" : "diesem Kommentar" }}
            bannen?
          </p>
          <UTextarea
            v-model="banReason"
            placeholder="Begründung (Pflicht intern, im Audit-Log persistiert)…"
            :rows="3"
            class="w-full"
          />
        </div>
      </template>
      <template #footer>
        <div class="flex justify-end gap-2 w-full">
          <UButton
            color="neutral"
            variant="ghost"
            :disabled="anyBusy"
            @click="banOpen = false"
          >
            Abbrechen
          </UButton>
          <UButton color="error" :loading="anyBusy" @click="confirmBan">
            Bannen
          </UButton>
        </div>
      </template>
    </UModal>
  </div>
</template>

<script setup lang="ts">
import type {
  ModerationItem,
  ModerationQueueResponse,
} from "~/server/api/moderation/queue.get";

definePageMeta({ middleware: "admin-auth" });

const toast = useToast();

const items = ref<ModerationItem[]>([]);
const nextCursor = ref<string | null>(null);
const pending = ref(false);
const error = ref<{ statusMessage?: string; message?: string } | null>(null);

async function fetchPage(cursor: string | null = null) {
  const query: Record<string, string> = {};
  if (cursor) query.cursor = cursor;
  return $fetch<ModerationQueueResponse>("/api/moderation/queue", { query });
}

async function reload() {
  pending.value = true;
  error.value = null;
  try {
    const res = await fetchPage(null);
    items.value = res.items;
    nextCursor.value = res.nextCursor;
  } catch (err: any) {
    error.value = {
      statusMessage: err?.statusMessage,
      message: err?.message,
    };
  } finally {
    pending.value = false;
  }
}

const loadingMore = ref(false);
async function loadMore() {
  if (!nextCursor.value || loadingMore.value) return;
  loadingMore.value = true;
  try {
    const res = await fetchPage(nextCursor.value);
    items.value = [...items.value, ...res.items];
    nextCursor.value = res.nextCursor;
  } catch (err: any) {
    toast.add({
      title: "Laden fehlgeschlagen",
      description: err?.statusMessage ?? err?.message ?? "Unbekannter Fehler",
      color: "error",
      icon: "heroicons:exclamation-triangle",
    });
  } finally {
    loadingMore.value = false;
  }
}

// Initial-load — client-side only (Auth-Middleware redirected sonst SSR).
onMounted(() => {
  reload();
});

// ─── Helpers ─────────────────────────────────────────────────────────────────

function shortId(id: string): string {
  if (!id) return "—";
  return id.slice(0, 8);
}

function formatDate(iso: string): string {
  if (!iso) return "—";
  try {
    return new Date(iso).toLocaleString("de-DE", {
      year: "numeric",
      month: "2-digit",
      day: "2-digit",
      hour: "2-digit",
      minute: "2-digit",
    });
  } catch {
    return iso;
  }
}

function truncate(s: string, max: number): string {
  if (!s) return "";
  if (s.length <= max) return s;
  return s.slice(0, max) + "…";
}

// ─── Action-Busy-State ───────────────────────────────────────────────────────

type ActionKind = "dismiss" | "delete" | "ban";

const busyKey = ref<string | null>(null); // "{type}:{id}:{action}"

function busy(item: ModerationItem, action: ActionKind): boolean {
  return busyKey.value === `${item.type}:${item.id}:${action}`;
}

const anyBusy = computed(() => busyKey.value !== null);

// ─── Dismiss ─────────────────────────────────────────────────────────────────

async function onDismiss(item: ModerationItem) {
  if (anyBusy.value) return;
  busyKey.value = `${item.type}:${item.id}:dismiss`;
  try {
    await $fetch(`/api/moderation/${item.id}/dismiss`, {
      method: "POST",
      body: { type: item.type },
    });
    toast.add({
      title: "Flag gelöscht",
      description: item.type === "post" ? "Post" : "Kommentar",
      color: "success",
      icon: "heroicons:check-circle",
    });
    items.value = items.value.filter(
      (i) => !(i.id === item.id && i.type === item.type),
    );
  } catch (err: any) {
    toast.add({
      title: "Dismiss fehlgeschlagen",
      description: err?.statusMessage ?? err?.message ?? "Unbekannter Fehler",
      color: "error",
      icon: "heroicons:exclamation-triangle",
    });
  } finally {
    busyKey.value = null;
  }
}

// ─── Delete ──────────────────────────────────────────────────────────────────

const deleteOpen = ref(false);
const deleteTarget = ref<ModerationItem | null>(null);
const deleteReason = ref("");

function askDelete(item: ModerationItem) {
  if (anyBusy.value) return;
  deleteTarget.value = item;
  deleteReason.value = "";
  deleteOpen.value = true;
}

async function confirmDelete() {
  const target = deleteTarget.value;
  if (!target || anyBusy.value) return;
  busyKey.value = `${target.type}:${target.id}:delete`;
  try {
    await $fetch(`/api/moderation/${target.id}/delete`, {
      method: "POST",
      body: {
        type: target.type,
        reason: deleteReason.value || undefined,
      },
    });
    toast.add({
      title: "Inhalt gelöscht",
      description: "Original im Audit-Log persistiert",
      color: "warning",
      icon: "heroicons:trash",
    });
    deleteOpen.value = false;
    deleteTarget.value = null;
    deleteReason.value = "";
    // Item lokal als gelöscht markieren statt aus Liste entfernen — Admin
    // sieht weiter dass es bearbeitet wurde, kann anschließend dismiss-en.
    items.value = items.value.map((i) =>
      i.id === target.id && i.type === target.type
        ? { ...i, isDeleted: true, content: "" }
        : i,
    );
  } catch (err: any) {
    toast.add({
      title: "Delete fehlgeschlagen",
      description: err?.statusMessage ?? err?.message ?? "Unbekannter Fehler",
      color: "error",
      icon: "heroicons:exclamation-triangle",
    });
  } finally {
    busyKey.value = null;
  }
}

// ─── Ban-User ────────────────────────────────────────────────────────────────

const banOpen = ref(false);
const banTarget = ref<ModerationItem | null>(null);
const banReason = ref("");

function askBan(item: ModerationItem) {
  if (anyBusy.value) return;
  banTarget.value = item;
  banReason.value = "";
  banOpen.value = true;
}

async function confirmBan() {
  const target = banTarget.value;
  if (!target || anyBusy.value) return;
  busyKey.value = `${target.type}:${target.id}:ban`;
  try {
    await $fetch(`/api/moderation/${target.id}/ban-user`, {
      method: "POST",
      body: {
        type: target.type,
        reason: banReason.value || undefined,
      },
    });
    toast.add({
      title: "User gebannt",
      description: target.author?.nickname || shortId(target.userId),
      color: "error",
      icon: "heroicons:no-symbol",
    });
    banOpen.value = false;
    banTarget.value = null;
    banReason.value = "";
    // Refresh — andere Items vom selben User sind jetzt auch ban-betroffen.
    await reload();
  } catch (err: any) {
    toast.add({
      title: "Ban fehlgeschlagen",
      description: err?.statusMessage ?? err?.message ?? "Unbekannter Fehler",
      color: "error",
      icon: "heroicons:exclamation-triangle",
    });
  } finally {
    busyKey.value = null;
  }
}
</script>
