import { usePrisma } from "../utils/prisma";

// ─────────────────────────────────────────────────────────────────────────────
// Moderation-Queue — DB-Layer
//
// Wird ausschließlich vom Admin-Backend (/api/admin/moderation/*) verwendet.
// Reported-Marker ist `isModerated=true` auf CommunityPost / CommunityReply
// (siehe Migration 20260509_moderation_queue).
//
// Audit-Trail: jede Aktion (dismiss / delete / ban_user) schreibt einen
// `moderation_actions`-Eintrag inkl. content-snapshot. Original-Reporter wird
// nicht persistiert (anonymous-report-Convention, DSGVO-Datenminimierung).
// ─────────────────────────────────────────────────────────────────────────────

const MAX_LIMIT = 100;
const DEFAULT_LIMIT = 50;

export type ModerationItemType = "post" | "comment";

export type ModerationQueueItem = {
  id: string;
  type: ModerationItemType;
  content: string;
  postId: string | null;
  userId: string;
  reportedAt: Date | null;
  createdAt: Date;
  isDeleted: boolean;
  author: {
    id: string;
    nickname: string | null;
    avatar: string | null;
    plan: string;
  } | null;
};

export type ListQueueOpts = {
  cursor?: string;
  limit?: number;
};

/**
 * Liste der gemeldeten (isModerated=true) Posts + Comments.
 *
 * Items mit reportedAt=null (legacy-flagged ohne Timestamp) werden
 * trotzdem ausgeliefert und ans Ende der Sortierung gestellt.
 *
 * Cursor: opaker String "{type}:{id}"; nextCursor=null → Ende.
 */
export async function listModerationQueue(opts: ListQueueOpts = {}): Promise<{
  items: ModerationQueueItem[];
  nextCursor: string | null;
}> {
  const db = usePrisma();
  const limit = Math.min(Math.max(opts.limit ?? DEFAULT_LIMIT, 1), MAX_LIMIT);

  // Cursor-Parsing — Format: "{type}:{uuid}". Robuster Fallback auf null
  // bei korruptem Cursor (treat as no-cursor).
  let cursorPostId: string | null = null;
  let cursorReplyId: string | null = null;
  if (opts.cursor) {
    const [t, id] = opts.cursor.split(":");
    if (t === "post" && id) cursorPostId = id;
    else if (t === "comment" && id) cursorReplyId = id;
  }

  // Wir holen pro Typ limit+1 — danach in-memory mergen + sortieren.
  // Klein genug für admin-queue (typisch <100 reports gleichzeitig).
  const [posts, replies] = await Promise.all([
    db.communityPost.findMany({
      where: { isModerated: true },
      orderBy: [{ reportedAt: "desc" }, { id: "desc" }],
      take: limit + 1,
      ...(cursorPostId ? { cursor: { id: cursorPostId }, skip: 1 } : {}),
      select: {
        id: true,
        userId: true,
        content: true,
        reportedAt: true,
        createdAt: true,
        isDeleted: true,
        author: {
          select: {
            id: true,
            nickname: true,
            avatar: true,
            plan: true,
          },
        },
      },
    }),
    db.communityReply.findMany({
      where: { isModerated: true },
      orderBy: [{ reportedAt: "desc" }, { id: "desc" }],
      take: limit + 1,
      ...(cursorReplyId ? { cursor: { id: cursorReplyId }, skip: 1 } : {}),
      select: {
        id: true,
        postId: true,
        userId: true,
        content: true,
        reportedAt: true,
        createdAt: true,
        isDeleted: true,
        author: {
          select: {
            id: true,
            nickname: true,
            avatar: true,
            plan: true,
          },
        },
      },
    }),
  ]);

  const merged: ModerationQueueItem[] = [
    ...posts.map((p) => ({
      id: p.id,
      type: "post" as const,
      content: p.content,
      postId: null,
      userId: p.userId,
      reportedAt: p.reportedAt,
      createdAt: p.createdAt,
      isDeleted: p.isDeleted,
      author: p.author,
    })),
    ...replies.map((r) => ({
      id: r.id,
      type: "comment" as const,
      content: r.content,
      postId: r.postId,
      userId: r.userId,
      reportedAt: r.reportedAt,
      createdAt: r.createdAt,
      isDeleted: r.isDeleted,
      author: r.author,
    })),
  ];

  // reportedAt desc, NULL ans Ende; Tie-Break: createdAt desc.
  merged.sort((a, b) => {
    const aTs = a.reportedAt?.getTime() ?? 0;
    const bTs = b.reportedAt?.getTime() ?? 0;
    if (aTs !== bTs) return bTs - aTs;
    return b.createdAt.getTime() - a.createdAt.getTime();
  });

  const items = merged.slice(0, limit);
  // nextCursor — nimm letztes Item, encode "{type}:{id}". Heuristik: wenn
  // wir genau `limit` Items haben UND mind. einer der DB-Calls limit+1
  // geliefert hat, dann gibt's mehr.
  const hasMore =
    posts.length > limit ||
    replies.length > limit ||
    merged.length > items.length;
  const last = items[items.length - 1];
  const nextCursor = hasMore && last ? `${last.type}:${last.id}` : null;

  return { items, nextCursor };
}

/**
 * Dismiss → Flag clear ohne Aktion. isModerated=false, reportedAt=null.
 * Schreibt audit-log "dismiss".
 */
export async function dismissModerationItem(
  type: ModerationItemType,
  id: string,
  adminUserId: string | null,
): Promise<{ ok: true }> {
  const db = usePrisma();

  const target =
    type === "post"
      ? await db.communityPost.findUnique({
          where: { id },
          select: { id: true, content: true },
        })
      : await db.communityReply.findUnique({
          where: { id },
          select: { id: true, content: true },
        });

  if (!target) {
    throw createError({
      statusCode: 404,
      message: `${type} nicht gefunden`,
    });
  }

  if (type === "post") {
    await db.communityPost.update({
      where: { id },
      data: { isModerated: false, reportedAt: null },
    });
  } else {
    await db.communityReply.update({
      where: { id },
      data: { isModerated: false, reportedAt: null },
    });
  }

  await db.moderationAction.create({
    data: {
      targetType: type,
      targetId: id,
      action: "dismiss",
      adminUserId,
      contentSnapshot: target.content,
    },
  });

  return { ok: true };
}

/**
 * Soft-Delete: content="", isDeleted=true. isModerated bleibt true (audit-trail
 * — Admin sieht in queue-Filter „deleted" was schon weg ist). Original-content
 * wird in moderation_actions.contentSnapshot persistiert.
 */
export async function deleteModerationItem(
  type: ModerationItemType,
  id: string,
  adminUserId: string | null,
  reason?: string | null,
): Promise<{ ok: true }> {
  const db = usePrisma();

  const target =
    type === "post"
      ? await db.communityPost.findUnique({
          where: { id },
          select: { id: true, content: true },
        })
      : await db.communityReply.findUnique({
          where: { id },
          select: { id: true, content: true },
        });

  if (!target) {
    throw createError({
      statusCode: 404,
      message: `${type} nicht gefunden`,
    });
  }

  const now = new Date();

  if (type === "post") {
    await db.communityPost.update({
      where: { id },
      data: {
        content: "",
        isDeleted: true,
        deletedAt: now,
      },
    });
  } else {
    await db.communityReply.update({
      where: { id },
      data: {
        content: "",
        isDeleted: true,
        deletedAt: now,
      },
    });
  }

  await db.moderationAction.create({
    data: {
      targetType: type,
      targetId: id,
      action: "delete",
      adminUserId,
      contentSnapshot: target.content,
      reason: reason ?? null,
    },
  });

  return { ok: true };
}

/**
 * Ban-User wegen content. Reuses Profile.banned + bannedAt + bannedReason
 * (siehe db/adminUsers.ts updateAdminUser-Pattern). Schreibt audit-log "ban_user".
 *
 * NOTE: Hier wird zwingend nur der Profile-Patch ausgeführt. Der Caller (Endpoint)
 * sollte zusätzlich `updateAdminUser({ banned: true })` aus adminUsers.ts nutzen,
 * falls beide Endpoints denselben Pfad teilen sollen — aktuell duplizieren wir
 * den minimalen Patch hier um die DB-Layer-Trennung sauber zu halten.
 */
export async function banUserFromModerationItem(
  type: ModerationItemType,
  id: string,
  adminUserId: string | null,
  reason?: string | null,
): Promise<{ ok: true; bannedUserId: string }> {
  const db = usePrisma();

  const target =
    type === "post"
      ? await db.communityPost.findUnique({
          where: { id },
          select: { id: true, content: true, userId: true },
        })
      : await db.communityReply.findUnique({
          where: { id },
          select: { id: true, content: true, userId: true },
        });

  if (!target) {
    throw createError({
      statusCode: 404,
      message: `${type} nicht gefunden`,
    });
  }

  await db.profile.update({
    where: { id: target.userId },
    data: {
      banned: true,
      bannedAt: new Date(),
      bannedReason: reason ?? `Moderation: ${type} ${id}`,
    },
  });

  await db.moderationAction.create({
    data: {
      targetType: type,
      targetId: id,
      action: "ban_user",
      adminUserId,
      contentSnapshot: target.content,
      reason: reason ?? null,
    },
  });

  return { ok: true, bannedUserId: target.userId };
}
