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

// ─── Gruppen-Chat ─────────────────────────────────────────────────────────────

export async function getChatMessages(limit = 100) {
  const db = usePrisma();
  return db.chatMessage.findMany({
    where: { roomId: null },
    orderBy: { createdAt: "asc" },
    take: limit,
    select: { id: true, content: true, createdAt: true, userId: true },
  });
}

export async function createChatMessage(userId: string, content: string) {
  const db = usePrisma();
  return db.chatMessage.create({
    data: { userId, content, roomId: null },
    select: { id: true, content: true, createdAt: true, userId: true },
  });
}

// ─── Direktnachrichten ───────────────────────────────────────────────────────

export async function sendDirectMessage(
  senderId: string,
  receiverId: string,
  content: string,
  opts?: {
    replyToId?: string;
    attachmentUrl?: string;
    attachmentType?: string;
    attachmentName?: string;
  },
) {
  const db = usePrisma();
  const msg = await db.directMessage.create({
    data: {
      senderId,
      receiverId,
      content,
      replyToId: opts?.replyToId || null,
      attachmentUrl: opts?.attachmentUrl || null,
      attachmentType: opts?.attachmentType || null,
      attachmentName: opts?.attachmentName || null,
    },
    select: {
      id: true,
      content: true,
      createdAt: true,
      replyToId: true,
      attachmentUrl: true,
      attachmentType: true,
      attachmentName: true,
      likesCount: true,
      replyTo: {
        select: { id: true, senderId: true, content: true },
      },
    },
  });

  // Push-Notification (fire-and-forget — blockt Response nicht)
  void (async () => {
    try {
      const { sendChatPush, getDisplayName, truncatePreview } = await import(
        "../services/push"
      );
      const senderName = await getDisplayName(senderId);
      // Call-DM-Eintrag (attachmentType='call', attachmentName='<kind>:<state>:<durSec>')
      // → schöne Preview statt leeren String. Bei verpassten/abgelehnten Calls
      // ist content immer "".
      let basePreview = content;
      if (opts?.attachmentType === "call" && opts.attachmentName) {
        const [, state, durSecStr] = opts.attachmentName.split(":");
        const durSec = parseInt(durSecStr ?? "0", 10) || 0;
        if (state === "unanswered") basePreview = "📞 Verpasster Anruf";
        else if (state === "declined") basePreview = "📞 Anruf abgelehnt";
        else if (state === "failed") basePreview = "📞 Anruf fehlgeschlagen";
        else if (state === "busy") basePreview = "📞 Besetzt";
        else if (state === "ended") {
          const mm = Math.floor(durSec / 60);
          const ss = String(durSec % 60).padStart(2, "0");
          basePreview = `📞 Anruf (${mm}:${ss})`;
        } else {
          basePreview = "📞 Anruf";
        }
      } else if (!basePreview) {
        basePreview =
          opts?.attachmentType === "audio" ? "🎤 Sprachnachricht" :
          (opts?.attachmentType === "image" || opts?.attachmentUrl) ? "📷 Foto" : "";
      }
      const preview = truncatePreview(basePreview);
      console.log(`[dm-push] sender=${senderId} receiver=${receiverId} preview="${preview.slice(0, 30)}"`);
      await sendChatPush({
        receiverId,
        senderName,
        preview,
        data: { type: "dm", targetId: senderId, messageId: msg.id },
      });
    } catch (err) {
      console.error("[dm-push] failed:", err);
    }
  })();

  return msg;
}

export async function getDmHistory(
  userId: string,
  partnerId: string,
  page = 1,
  limit = 50,
) {
  const db = usePrisma();
  const offset = (page - 1) * limit;
  return db.directMessage.findMany({
    where: {
      OR: [
        { senderId: userId, receiverId: partnerId },
        { senderId: partnerId, receiverId: userId },
      ],
    },
    orderBy: { createdAt: "desc" },
    skip: offset,
    take: limit,
    select: {
      id: true,
      senderId: true,
      receiverId: true,
      content: true,
      createdAt: true,
      readAt: true,
      replyToId: true,
      attachmentUrl: true,
      attachmentType: true,
      attachmentName: true,
      likesCount: true,
      deletedAt: true,
      reactions: {
        select: { userId: true, emoji: true },
      },
      replyTo: {
        select: { id: true, senderId: true, content: true },
      },
    },
  });
}

/**
 * Toggle einer Emoji-Reaktion auf eine DM (WhatsApp-Verhalten):
 *  - kein Eintrag      → Reaktion anlegen
 *  - gleiches Emoji    → Reaktion entfernen (toggle off)
 *  - anderes Emoji     → Reaktion ersetzen
 * Eine Reaktion pro User pro Message (PK user+message).
 */
export async function toggleDmReaction(
  userId: string,
  messageId: string,
  emoji: string,
) {
  const db = usePrisma();
  const existing = await db.directMessageReaction.findUnique({
    where: { userId_messageId: { userId, messageId } },
  });
  if (existing) {
    if (existing.emoji === emoji) {
      await db.directMessageReaction.delete({
        where: { userId_messageId: { userId, messageId } },
      });
      return { emoji: null as string | null };
    }
    const updated = await db.directMessageReaction.update({
      where: { userId_messageId: { userId, messageId } },
      data: { emoji },
    });
    return { emoji: updated.emoji };
  }
  const created = await db.directMessageReaction.create({
    data: { userId, messageId, emoji },
  });
  return { emoji: created.emoji };
}

/**
 * Soft-Delete einer DM (Tombstone). Nur eigene Nachrichten löschbar.
 * @returns true wenn gelöscht, false wenn nicht erlaubt/nicht gefunden.
 */
export async function softDeleteDmMessage(userId: string, messageId: string) {
  const db = usePrisma();
  const res = await db.directMessage.updateMany({
    where: { id: messageId, senderId: userId, deletedAt: null },
    data: { deletedAt: new Date() },
  });
  return res.count > 0;
}

export async function markDmsAsRead(senderId: string, receiverId: string) {
  const db = usePrisma();
  return db.directMessage.updateMany({
    where: { senderId, receiverId, readAt: null },
    data: { readAt: new Date() },
  });
}

export type DmConversationRow = {
  id: string;
  senderId: string;
  receiverId: string;
  content: string;
  createdAt: Date;
  readAt: Date | null;
  attachmentType: string | null;
};

export async function getDmConversations(userId: string): Promise<DmConversationRow[]> {
  const db = usePrisma();
  // Eine Zeile pro Gesprächspartner: die jeweils NEUESTE DM. Postgres
  // DISTINCT ON (partner) + ORDER BY partner, created_at DESC erledigt das
  // DB-seitig in EINER Query (index-gestützt), statt 500 Rows zu ziehen und
  // in JS zu deduplizieren. Spalten werden auf camelCase aliased, damit die
  // Rows shape-kompatibel zur vorherigen Prisma-Selection bleiben.
  return db.$queryRaw<DmConversationRow[]>`
    SELECT DISTINCT ON (partner_id)
      id,
      sender_id        AS "senderId",
      receiver_id      AS "receiverId",
      content,
      created_at       AS "createdAt",
      read_at          AS "readAt",
      attachment_type  AS "attachmentType"
    FROM (
      SELECT *,
        CASE WHEN sender_id = ${userId}::uuid THEN receiver_id ELSE sender_id END AS partner_id
      FROM "rebreak"."direct_messages"
      WHERE sender_id = ${userId}::uuid OR receiver_id = ${userId}::uuid
    ) sub
    ORDER BY partner_id, created_at DESC
  `;
}

export async function countUnreadDms(receiverId: string) {
  const db = usePrisma();
  const rows = await db.directMessage.findMany({
    where: { receiverId, readAt: null },
    select: { senderId: true },
  });
  const byPartner: Record<string, number> = {};
  for (const r of rows) {
    byPartner[r.senderId] = (byPartner[r.senderId] ?? 0) + 1;
  }
  return byPartner;
}
