import { z } from 'zod'
import { router, memberProcedure, adminProcedure } from '../trpc'
import { sendPushNotifications } from '@/lib/notifications'

const NewsInput = z.object({
  title: z.string().min(3),
  body: z.string().min(10),
  kategorie: z.enum(['Wichtig', 'Pruefung', 'Foerderung', 'Veranstaltung', 'Allgemein']),
  publishedAt: z.string().datetime().optional().nullable(),
  attachments: z
    .array(
      z.object({
        name: z.string(),
        storagePath: z.string(),
        sizeBytes: z.number().int().optional().nullable(),
        mimeType: z.string().optional().nullable(),
      })
    )
    .optional(),
})

export const newsRouter = router({
  /**
   * List published news for org members
   */
  list: memberProcedure
    .input(
      z.object({
        kategorie: z
          .enum(['Wichtig', 'Pruefung', 'Foerderung', 'Veranstaltung', 'Allgemein'])
          .optional(),
        includeUnpublished: z.boolean().default(false),
      })
    )
    .query(async ({ ctx, input }) => {
      const news = await ctx.prisma.news.findMany({
        where: {
          orgId: ctx.orgId,
          ...(input.kategorie && { kategorie: input.kategorie }),
          ...(!input.includeUnpublished && { publishedAt: { not: null } }),
          ...(input.includeUnpublished &&
            ctx.role !== 'admin' && { publishedAt: { not: null } }),
        },
        include: {
          author: { select: { name: true } },
          attachments: true,
          reads: {
            where: { userId: ctx.session.user.id },
            select: { id: true },
          },
        },
        orderBy: [{ publishedAt: 'desc' }, { createdAt: 'desc' }],
      })

      return news.map((n) => ({
        ...n,
        isRead: n.reads.length > 0,
        reads: undefined,
      }))
    }),

  /**
   * Get single news article
   */
  byId: memberProcedure
    .input(z.object({ id: z.string() }))
    .query(async ({ ctx, input }) => {
      const news = await ctx.prisma.news.findFirstOrThrow({
        where: {
          id: input.id,
          orgId: ctx.orgId,
          ...(ctx.role !== 'admin' && { publishedAt: { not: null } }),
        },
        include: {
          author: { select: { name: true, betrieb: true } },
          attachments: true,
        },
      })
      return news
    }),

  /**
   * Mark news as read
   */
  markRead: memberProcedure
    .input(z.object({ newsId: z.string() }))
    .mutation(async ({ ctx, input }) => {
      await ctx.prisma.newsRead.upsert({
        where: {
          newsId_userId: { newsId: input.newsId, userId: ctx.session.user.id },
        },
        update: {},
        create: {
          newsId: input.newsId,
          userId: ctx.session.user.id,
        },
      })
      return { success: true }
    }),

  /**
   * Create news article (admin only)
   */
  create: adminProcedure.input(NewsInput).mutation(async ({ ctx, input }) => {
    const member = await ctx.prisma.member.findFirst({
      where: { userId: ctx.session.user.id, orgId: ctx.orgId },
    })

    const news = await ctx.prisma.news.create({
      data: {
        orgId: ctx.orgId,
        authorId: member?.id,
        title: input.title,
        body: input.body,
        kategorie: input.kategorie,
        publishedAt: input.publishedAt ? new Date(input.publishedAt) : null,
        ...(input.attachments && input.attachments.length > 0 && {
          attachments: {
            create: input.attachments.map((a) => ({
              name: a.name,
              storagePath: a.storagePath,
              sizeBytes: a.sizeBytes,
              mimeType: a.mimeType,
            })),
          },
        }),
      },
    })

    // Trigger push notifications if publishing now
    if (news.publishedAt) {
      sendPushNotifications(ctx.orgId, news.title).catch(console.error)
    }

    return news
  }),

  /**
   * Update news article (admin only)
   */
  update: adminProcedure
    .input(z.object({ id: z.string(), data: NewsInput.partial() }))
    .mutation(async ({ ctx, input }) => {
      const existing = await ctx.prisma.news.findFirst({
        where: { id: input.id, orgId: ctx.orgId },
      })

      if (!existing) {
        throw new Error('News not found or access denied')
      }

      const wasUnpublished = !existing.publishedAt

      const { attachments, ...restData } = input.data

      const news = await ctx.prisma.news.update({
        where: { id: input.id },
        data: {
          ...restData,
          publishedAt: restData.publishedAt
            ? new Date(restData.publishedAt)
            : restData.publishedAt === null
              ? null
              : undefined,
          ...(attachments && {
            attachments: {
              deleteMany: {},
              create: attachments.map((a) => ({
                name: a.name,
                storagePath: a.storagePath,
                sizeBytes: a.sizeBytes,
                mimeType: a.mimeType,
              })),
            },
          }),
        },
      })

      // Trigger push if just published
      if (wasUnpublished && news.publishedAt && news.title) {
        sendPushNotifications(ctx.orgId, news.title).catch(console.error)
      }

      return news
    }),

  /**
   * Delete news article (admin only)
   */
  delete: adminProcedure
    .input(z.object({ id: z.string() }))
    .mutation(async ({ ctx, input }) => {
      await ctx.prisma.news.deleteMany({
        where: { id: input.id, orgId: ctx.orgId },
      })
      return { success: true }
    }),

  /**
   * Get read stats for admin
   */
  readStats: adminProcedure
    .input(z.object({ newsId: z.string() }))
    .query(async ({ ctx, input }) => {
      const [totalMembers, readers] = await Promise.all([
        ctx.prisma.member.count({ where: { orgId: ctx.orgId, status: 'aktiv' } }),
        ctx.prisma.newsRead.count({ where: { newsId: input.newsId } }),
      ])
      return { totalMembers, readers, readRate: totalMembers ? readers / totalMembers : 0 }
    }),
})
