import { z } from 'zod'
import { router, protectedProcedure, adminProcedure } from '../trpc'
import { getPresignedUrl } from '@/lib/minio'

// Bucket for partner logos
export const PARTNER_BUCKET = 'mopc-partners'

export const partnerRouter = router({
  /**
   * List all partners (admin view)
   */
  list: adminProcedure
    .input(
      z.object({
        programId: z.string().optional(),
        partnerType: z.enum(['SPONSOR', 'PARTNER', 'SUPPORTER', 'MEDIA', 'OTHER']).optional(),
        visibility: z.enum(['ADMIN_ONLY', 'JURY_VISIBLE', 'PUBLIC']).optional(),
        isActive: z.boolean().optional(),
        page: z.number().int().min(1).default(1),
        perPage: z.number().int().min(1).max(100).default(50),
      })
    )
    .query(async ({ ctx, input }) => {
      const where: Record<string, unknown> = {}

      if (input.programId !== undefined) {
        where.programId = input.programId
      }
      if (input.partnerType) {
        where.partnerType = input.partnerType
      }
      if (input.visibility) {
        where.visibility = input.visibility
      }
      if (input.isActive !== undefined) {
        where.isActive = input.isActive
      }

      const [data, total] = await Promise.all([
        ctx.prisma.partner.findMany({
          where,
          include: {
            program: { select: { id: true, name: true, year: true } },
          },
          orderBy: [{ sortOrder: 'asc' }, { name: 'asc' }],
          skip: (input.page - 1) * input.perPage,
          take: input.perPage,
        }),
        ctx.prisma.partner.count({ where }),
      ])

      return {
        data,
        total,
        page: input.page,
        perPage: input.perPage,
        totalPages: Math.ceil(total / input.perPage),
      }
    }),

  /**
   * Get partners visible to jury members
   */
  getJuryVisible: protectedProcedure
    .input(
      z.object({
        programId: z.string().optional(),
        partnerType: z.enum(['SPONSOR', 'PARTNER', 'SUPPORTER', 'MEDIA', 'OTHER']).optional(),
      })
    )
    .query(async ({ ctx, input }) => {
      const where: Record<string, unknown> = {
        isActive: true,
        visibility: { in: ['JURY_VISIBLE', 'PUBLIC'] },
      }

      if (input.programId) {
        where.OR = [{ programId: input.programId }, { programId: null }]
      }
      if (input.partnerType) {
        where.partnerType = input.partnerType
      }

      return ctx.prisma.partner.findMany({
        where,
        orderBy: [{ sortOrder: 'asc' }, { name: 'asc' }],
      })
    }),

  /**
   * Get public partners (for public website)
   */
  getPublic: protectedProcedure
    .input(
      z.object({
        programId: z.string().optional(),
        partnerType: z.enum(['SPONSOR', 'PARTNER', 'SUPPORTER', 'MEDIA', 'OTHER']).optional(),
      })
    )
    .query(async ({ ctx, input }) => {
      const where: Record<string, unknown> = {
        isActive: true,
        visibility: 'PUBLIC',
      }

      if (input.programId) {
        where.OR = [{ programId: input.programId }, { programId: null }]
      }
      if (input.partnerType) {
        where.partnerType = input.partnerType
      }

      return ctx.prisma.partner.findMany({
        where,
        orderBy: [{ sortOrder: 'asc' }, { name: 'asc' }],
      })
    }),

  /**
   * Get a single partner by ID
   */
  get: adminProcedure
    .input(z.object({ id: z.string() }))
    .query(async ({ ctx, input }) => {
      return ctx.prisma.partner.findUniqueOrThrow({
        where: { id: input.id },
        include: {
          program: { select: { id: true, name: true, year: true } },
        },
      })
    }),

  /**
   * Get logo URL for a partner
   */
  getLogoUrl: protectedProcedure
    .input(z.object({ id: z.string() }))
    .query(async ({ ctx, input }) => {
      const partner = await ctx.prisma.partner.findUniqueOrThrow({
        where: { id: input.id },
      })

      if (!partner.logoBucket || !partner.logoObjectKey) {
        return { url: null }
      }

      const url = await getPresignedUrl(partner.logoBucket, partner.logoObjectKey, 'GET', 900)
      return { url }
    }),

  /**
   * Create a new partner (admin only)
   */
  create: adminProcedure
    .input(
      z.object({
        programId: z.string().nullable(),
        name: z.string().min(1).max(255),
        description: z.string().optional(),
        website: z.string().url().optional(),
        partnerType: z.enum(['SPONSOR', 'PARTNER', 'SUPPORTER', 'MEDIA', 'OTHER']).default('PARTNER'),
        visibility: z.enum(['ADMIN_ONLY', 'JURY_VISIBLE', 'PUBLIC']).default('ADMIN_ONLY'),
        sortOrder: z.number().int().default(0),
        isActive: z.boolean().default(true),
        // Logo info (set after upload)
        logoFileName: z.string().optional(),
        logoBucket: z.string().optional(),
        logoObjectKey: z.string().optional(),
      })
    )
    .mutation(async ({ ctx, input }) => {
      const partner = await ctx.prisma.partner.create({
        data: input,
      })

      // Audit log
      await ctx.prisma.auditLog.create({
        data: {
          userId: ctx.user.id,
          action: 'CREATE',
          entityType: 'Partner',
          entityId: partner.id,
          detailsJson: { name: input.name, partnerType: input.partnerType },
          ipAddress: ctx.ip,
          userAgent: ctx.userAgent,
        },
      })

      return partner
    }),

  /**
   * Update a partner (admin only)
   */
  update: adminProcedure
    .input(
      z.object({
        id: z.string(),
        name: z.string().min(1).max(255).optional(),
        description: z.string().optional().nullable(),
        website: z.string().url().optional().nullable(),
        partnerType: z.enum(['SPONSOR', 'PARTNER', 'SUPPORTER', 'MEDIA', 'OTHER']).optional(),
        visibility: z.enum(['ADMIN_ONLY', 'JURY_VISIBLE', 'PUBLIC']).optional(),
        sortOrder: z.number().int().optional(),
        isActive: z.boolean().optional(),
        // Logo info
        logoFileName: z.string().optional().nullable(),
        logoBucket: z.string().optional().nullable(),
        logoObjectKey: z.string().optional().nullable(),
      })
    )
    .mutation(async ({ ctx, input }) => {
      const { id, ...data } = input

      const partner = await ctx.prisma.partner.update({
        where: { id },
        data,
      })

      // Audit log
      await ctx.prisma.auditLog.create({
        data: {
          userId: ctx.user.id,
          action: 'UPDATE',
          entityType: 'Partner',
          entityId: id,
          detailsJson: data,
          ipAddress: ctx.ip,
          userAgent: ctx.userAgent,
        },
      })

      return partner
    }),

  /**
   * Delete a partner (admin only)
   */
  delete: adminProcedure
    .input(z.object({ id: z.string() }))
    .mutation(async ({ ctx, input }) => {
      const partner = await ctx.prisma.partner.delete({
        where: { id: input.id },
      })

      // Audit log
      await ctx.prisma.auditLog.create({
        data: {
          userId: ctx.user.id,
          action: 'DELETE',
          entityType: 'Partner',
          entityId: input.id,
          detailsJson: { name: partner.name },
          ipAddress: ctx.ip,
          userAgent: ctx.userAgent,
        },
      })

      return partner
    }),

  /**
   * Get upload URL for a partner logo (admin only)
   */
  getUploadUrl: adminProcedure
    .input(
      z.object({
        fileName: z.string(),
        mimeType: z.string(),
      })
    )
    .mutation(async ({ input }) => {
      const timestamp = Date.now()
      const sanitizedName = input.fileName.replace(/[^a-zA-Z0-9.-]/g, '_')
      const objectKey = `logos/${timestamp}-${sanitizedName}`

      const url = await getPresignedUrl(PARTNER_BUCKET, objectKey, 'PUT', 3600)

      return {
        url,
        bucket: PARTNER_BUCKET,
        objectKey,
      }
    }),

  /**
   * Reorder partners (admin only)
   */
  reorder: adminProcedure
    .input(
      z.object({
        items: z.array(
          z.object({
            id: z.string(),
            sortOrder: z.number().int(),
          })
        ),
      })
    )
    .mutation(async ({ ctx, input }) => {
      await ctx.prisma.$transaction(
        input.items.map((item) =>
          ctx.prisma.partner.update({
            where: { id: item.id },
            data: { sortOrder: item.sortOrder },
          })
        )
      )

      // Audit log
      await ctx.prisma.auditLog.create({
        data: {
          userId: ctx.user.id,
          action: 'REORDER',
          entityType: 'Partner',
          detailsJson: { count: input.items.length },
          ipAddress: ctx.ip,
          userAgent: ctx.userAgent,
        },
      })

      return { success: true }
    }),

  /**
   * Bulk update visibility (admin only)
   */
  bulkUpdateVisibility: adminProcedure
    .input(
      z.object({
        ids: z.array(z.string()),
        visibility: z.enum(['ADMIN_ONLY', 'JURY_VISIBLE', 'PUBLIC']),
      })
    )
    .mutation(async ({ ctx, input }) => {
      await ctx.prisma.partner.updateMany({
        where: { id: { in: input.ids } },
        data: { visibility: input.visibility },
      })

      // Audit log
      await ctx.prisma.auditLog.create({
        data: {
          userId: ctx.user.id,
          action: 'BULK_UPDATE',
          entityType: 'Partner',
          detailsJson: { ids: input.ids, visibility: input.visibility },
          ipAddress: ctx.ip,
          userAgent: ctx.userAgent,
        },
      })

      return { updated: input.ids.length }
    }),
})
