import { z } from 'zod'
import { router, memberProcedure } from '../trpc'
import { TRPCError } from '@trpc/server'

export const messagesRouter = router({
  // List all conversations for the current member
  getConversations: memberProcedure.query(async ({ ctx }) => {
    const member = await ctx.prisma.member.findFirst({
      where: { userId: ctx.session.user.id, orgId: ctx.orgId },
    })
    if (!member) throw new TRPCError({ code: 'NOT_FOUND' })

    const convMembers = await ctx.prisma.conversationMember.findMany({
      where: { memberId: member.id },
      include: {
        conversation: {
          include: {
            members: {
              include: { member: { select: { id: true, name: true, betrieb: true, avatarUrl: true } } },
            },
            messages: {
              orderBy: { createdAt: 'desc' },
              take: 1,
              select: { body: true, createdAt: true, senderId: true },
            },
          },
        },
      },
      orderBy: { conversation: { updatedAt: 'desc' } },
    })

    return convMembers.map((cm) => {
      const other = cm.conversation.members.find((m) => m.memberId !== member.id)?.member
      const lastMsg = cm.conversation.messages[0] ?? null
      const unread =
        lastMsg &&
        (!cm.lastReadAt || lastMsg.createdAt > cm.lastReadAt) &&
        lastMsg.senderId !== member.id
      return {
        conversationId: cm.conversationId,
        other,
        lastMessage: lastMsg,
        hasUnread: !!unread,
        updatedAt: cm.conversation.updatedAt,
      }
    })
  }),

  // Get or create a 1-on-1 conversation between current member and another
  getOrCreate: memberProcedure
    .input(z.object({ otherMemberId: z.string() }))
    .mutation(async ({ ctx, input }) => {
      const member = await ctx.prisma.member.findFirst({
        where: { userId: ctx.session.user.id, orgId: ctx.orgId },
      })
      if (!member) throw new TRPCError({ code: 'NOT_FOUND' })

      const other = await ctx.prisma.member.findFirst({
        where: { id: input.otherMemberId, orgId: ctx.orgId },
      })
      if (!other) throw new TRPCError({ code: 'NOT_FOUND', message: 'Mitglied nicht gefunden' })

      // Find existing conversation between the two members in this org
      const existing = await ctx.prisma.conversation.findFirst({
        where: {
          orgId: ctx.orgId,
          members: { every: { memberId: { in: [member.id, other.id] } } },
          AND: [
            { members: { some: { memberId: member.id } } },
            { members: { some: { memberId: other.id } } },
          ],
        },
      })

      if (existing) return { conversationId: existing.id }

      const conv = await ctx.prisma.conversation.create({
        data: {
          orgId: ctx.orgId,
          members: {
            create: [{ memberId: member.id }, { memberId: other.id }],
          },
        },
      })
      return { conversationId: conv.id }
    }),

  // Get messages for a conversation
  getMessages: memberProcedure
    .input(z.object({ conversationId: z.string(), cursor: z.string().optional() }))
    .query(async ({ ctx, input }) => {
      const member = await ctx.prisma.member.findFirst({
        where: { userId: ctx.session.user.id, orgId: ctx.orgId },
      })
      if (!member) throw new TRPCError({ code: 'NOT_FOUND' })

      // Verify membership in conversation
      const cm = await ctx.prisma.conversationMember.findUnique({
        where: { conversationId_memberId: { conversationId: input.conversationId, memberId: member.id } },
      })
      if (!cm) throw new TRPCError({ code: 'FORBIDDEN' })

      const messages = await ctx.prisma.message.findMany({
        where: { conversationId: input.conversationId },
        include: { sender: { select: { id: true, name: true, avatarUrl: true } } },
        orderBy: { createdAt: 'desc' },
        take: 40,
        ...(input.cursor ? { skip: 1, cursor: { id: input.cursor } } : {}),
      })

      // Mark as read
      await ctx.prisma.conversationMember.update({
        where: { conversationId_memberId: { conversationId: input.conversationId, memberId: member.id } },
        data: { lastReadAt: new Date() },
      })

      return {
        messages: messages.reverse(),
        nextCursor: messages.length === 40 ? messages[0]?.id : undefined,
      }
    }),

  // Send a message
  sendMessage: memberProcedure
    .input(z.object({ conversationId: z.string(), body: z.string().min(1).max(2000) }))
    .mutation(async ({ ctx, input }) => {
      const member = await ctx.prisma.member.findFirst({
        where: { userId: ctx.session.user.id, orgId: ctx.orgId },
      })
      if (!member) throw new TRPCError({ code: 'NOT_FOUND' })

      const cm = await ctx.prisma.conversationMember.findUnique({
        where: { conversationId_memberId: { conversationId: input.conversationId, memberId: member.id } },
      })
      if (!cm) throw new TRPCError({ code: 'FORBIDDEN' })

      const message = await ctx.prisma.message.create({
        data: {
          conversationId: input.conversationId,
          senderId: member.id,
          body: input.body.trim(),
        },
        include: { sender: { select: { id: true, name: true, avatarUrl: true } } },
      })

      // Update conversation updatedAt so it sorts to top
      await ctx.prisma.conversation.update({
        where: { id: input.conversationId },
        data: { updatedAt: new Date() },
      })

      return message
    }),

  // Count total unread conversations
  unreadCount: memberProcedure.query(async ({ ctx }) => {
    const member = await ctx.prisma.member.findFirst({
      where: { userId: ctx.session.user.id, orgId: ctx.orgId },
    })
    if (!member) return { count: 0 }

    const convMembers = await ctx.prisma.conversationMember.findMany({
      where: { memberId: member.id },
      include: {
        conversation: {
          include: {
            messages: {
              orderBy: { createdAt: 'desc' },
              take: 1,
              select: { createdAt: true, senderId: true },
            },
          },
        },
      },
    })

    const count = convMembers.filter((cm) => {
      const last = cm.conversation.messages[0]
      return last && last.senderId !== member.id && (!cm.lastReadAt || last.createdAt > cm.lastReadAt)
    }).length

    return { count }
  }),
})
