import { z } from 'zod'
import { router, memberProcedure, adminProcedure } from '../trpc'

const TerminInput = z.object({
  titel: z.string().min(3),
  datum: z.string(), // ISO date string "YYYY-MM-DD"
  uhrzeit: z.string().optional(),
  endeDatum: z.string().optional().nullable(),
  endeUhrzeit: z.string().optional().nullable(),
  ort: z.string().optional(),
  adresse: z.string().optional(),
  typ: z.enum(['Pruefung', 'Versammlung', 'Kurs', 'Event', 'Sonstiges']),
  beschreibung: z.string().optional(),
  maxTeilnehmer: z.number().int().positive().optional().nullable(),
})

export const termineRouter = router({
  /**
   * List all termine for org
   */
  list: memberProcedure
    .input(
      z.object({
        upcoming: z.boolean().optional(),
        nurAngemeldet: z.boolean().optional(),
      })
    )
    .query(async ({ ctx, input }) => {
      const member = await ctx.prisma.member.findFirst({
        where: { userId: ctx.session.user.id, orgId: ctx.orgId },
      })

      const today = new Date()
      today.setHours(0, 0, 0, 0)

      const termine = await ctx.prisma.termin.findMany({
        where: {
          orgId: ctx.orgId,
          ...(input.upcoming && { datum: { gte: today } }),
          ...(!input.upcoming &&
            input.upcoming !== undefined && { datum: { lt: today } }),
          ...(input.nurAngemeldet &&
            member && {
              anmeldungen: { some: { memberId: member.id } },
            }),
        },
        include: {
          anmeldungen: {
            select: { memberId: true },
          },
        },
        orderBy: { datum: input.upcoming ? 'asc' : 'desc' },
      })

      return termine.map((t) => ({
        ...t,
        isAngemeldet: member
          ? t.anmeldungen.some((a) => a.memberId === member.id)
          : false,
        teilnehmerAnzahl: t.anmeldungen.length,
        anmeldungen: undefined,
      }))
    }),

  /**
   * Get single Termin
   */
  byId: memberProcedure
    .input(z.object({ id: z.string() }))
    .query(async ({ ctx, input }) => {
      const member = await ctx.prisma.member.findFirst({
        where: { userId: ctx.session.user.id, orgId: ctx.orgId },
      })

      const termin = await ctx.prisma.termin.findFirstOrThrow({
        where: { id: input.id, orgId: ctx.orgId },
        include: {
          anmeldungen: {
            include: {
              member: { select: { name: true, betrieb: true } },
            },
          },
        },
      })

      const isAngemeldet = member
        ? termin.anmeldungen.some((a) => a.memberId === member.id)
        : false

      return {
        ...termin,
        isAngemeldet,
        teilnehmerAnzahl: termin.anmeldungen.length,
        // Only expose member list to admins
        anmeldungen: ctx.role === 'admin' ? termin.anmeldungen : [],
      }
    }),

  /**
   * Anmelden / Abmelden
   */
  toggleAnmeldung: memberProcedure
    .input(z.object({ terminId: z.string() }))
    .mutation(async ({ ctx, input }) => {
      const member = await ctx.prisma.member.findFirstOrThrow({
        where: { userId: ctx.session.user.id, orgId: ctx.orgId },
      })

      const termin = await ctx.prisma.termin.findFirstOrThrow({
        where: { id: input.terminId, orgId: ctx.orgId },
        include: { anmeldungen: true },
      })

      const existing = termin.anmeldungen.find(
        (a) => a.memberId === member.id
      )

      if (existing) {
        // Abmelden
        await ctx.prisma.terminAnmeldung.delete({ where: { id: existing.id } })
        return { angemeldet: false }
      } else {
        // Check capacity
        if (
          termin.maxTeilnehmer &&
          termin.anmeldungen.length >= termin.maxTeilnehmer
        ) {
          throw new Error('Maximale Teilnehmerzahl erreicht')
        }
        await ctx.prisma.terminAnmeldung.create({
          data: { terminId: input.terminId, memberId: member.id },
        })
        return { angemeldet: true }
      }
    }),

  /**
   * Create Termin (admin only)
   */
  create: adminProcedure.input(TerminInput).mutation(async ({ ctx, input }) => {
    const termin = await ctx.prisma.termin.create({
      data: {
        orgId: ctx.orgId,
        ...input,
        datum: new Date(input.datum),
        endeDatum: input.endeDatum ? new Date(input.endeDatum) : null,
      },
    })
    return termin
  }),

  /**
   * Update Termin (admin only)
   */
  update: adminProcedure
    .input(z.object({ id: z.string(), data: TerminInput.partial() }))
    .mutation(async ({ ctx, input }) => {
      await ctx.prisma.termin.updateMany({
        where: { id: input.id, orgId: ctx.orgId },
        data: {
          ...input.data,
          ...(input.data.datum && { datum: new Date(input.data.datum) }),
          ...(input.data.endeDatum && { endeDatum: new Date(input.data.endeDatum) }),
        },
      })
      return { success: true }
    }),

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