import { z } from 'zod'
import { router, adminProcedure, superAdminProcedure, protectedProcedure } from '../trpc'
import { getWhatsAppProvider, getWhatsAppProviderType } from '@/lib/whatsapp'

export const settingsRouter = router({
  /**
   * Get all settings by category
   */
  getByCategory: adminProcedure
    .input(z.object({ category: z.string() }))
    .query(async ({ ctx, input }) => {
      const settings = await ctx.prisma.systemSettings.findMany({
        where: { category: input.category as any },
        orderBy: { key: 'asc' },
      })

      // Mask secret values for non-super-admins
      if (ctx.user.role !== 'SUPER_ADMIN') {
        return settings.map((s) => ({
          ...s,
          value: s.isSecret ? '********' : s.value,
        }))
      }

      return settings
    }),

  /**
   * Get a single setting
   */
  get: adminProcedure
    .input(z.object({ key: z.string() }))
    .query(async ({ ctx, input }) => {
      const setting = await ctx.prisma.systemSettings.findUnique({
        where: { key: input.key },
      })

      if (!setting) return null

      // Mask secret values for non-super-admins
      if (setting.isSecret && ctx.user.role !== 'SUPER_ADMIN') {
        return { ...setting, value: '********' }
      }

      return setting
    }),

  /**
   * Get multiple settings by keys (for client-side caching)
   */
  getMultiple: adminProcedure
    .input(z.object({ keys: z.array(z.string()) }))
    .query(async ({ ctx, input }) => {
      const settings = await ctx.prisma.systemSettings.findMany({
        where: { key: { in: input.keys } },
      })

      // Mask secret values for non-super-admins
      if (ctx.user.role !== 'SUPER_ADMIN') {
        return settings.map((s) => ({
          ...s,
          value: s.isSecret ? '********' : s.value,
        }))
      }

      return settings
    }),

  /**
   * Update a setting (super admin only for secrets)
   */
  update: superAdminProcedure
    .input(
      z.object({
        key: z.string(),
        value: z.string(),
      })
    )
    .mutation(async ({ ctx, input }) => {
      const setting = await ctx.prisma.systemSettings.update({
        where: { key: input.key },
        data: {
          value: input.value,
          updatedBy: ctx.user.id,
        },
      })

      // Audit log (don't log actual value for secrets)
      await ctx.prisma.auditLog.create({
        data: {
          userId: ctx.user.id,
          action: 'UPDATE_SETTING',
          entityType: 'SystemSettings',
          entityId: setting.id,
          detailsJson: {
            key: input.key,
            isSecret: setting.isSecret,
          },
          ipAddress: ctx.ip,
          userAgent: ctx.userAgent,
        },
      })

      return setting
    }),

  /**
   * Update multiple settings at once (upsert - creates if not exists)
   */
  updateMultiple: superAdminProcedure
    .input(
      z.object({
        settings: z.array(
          z.object({
            key: z.string(),
            value: z.string(),
            category: z.enum(['AI', 'BRANDING', 'EMAIL', 'STORAGE', 'SECURITY', 'DEFAULTS', 'WHATSAPP']).optional(),
          })
        ),
      })
    )
    .mutation(async ({ ctx, input }) => {
      // Infer category from key prefix if not provided
      const inferCategory = (key: string): 'AI' | 'BRANDING' | 'EMAIL' | 'STORAGE' | 'SECURITY' | 'DEFAULTS' | 'WHATSAPP' => {
        if (key.startsWith('openai') || key.startsWith('ai_')) return 'AI'
        if (key.startsWith('smtp_') || key.startsWith('email_')) return 'EMAIL'
        if (key.startsWith('storage_') || key.startsWith('local_storage') || key.startsWith('max_file') || key.startsWith('avatar_') || key.startsWith('allowed_file')) return 'STORAGE'
        if (key.startsWith('brand_') || key.startsWith('logo_') || key.startsWith('primary_') || key.startsWith('theme_')) return 'BRANDING'
        if (key.startsWith('whatsapp_')) return 'WHATSAPP'
        if (key.startsWith('security_') || key.startsWith('session_')) return 'SECURITY'
        return 'DEFAULTS'
      }

      const results = await Promise.all(
        input.settings.map((s) =>
          ctx.prisma.systemSettings.upsert({
            where: { key: s.key },
            update: {
              value: s.value,
              updatedBy: ctx.user.id,
            },
            create: {
              key: s.key,
              value: s.value,
              category: s.category || inferCategory(s.key),
              updatedBy: ctx.user.id,
            },
          })
        )
      )

      // Audit log
      await ctx.prisma.auditLog.create({
        data: {
          userId: ctx.user.id,
          action: 'UPDATE_SETTINGS_BATCH',
          entityType: 'SystemSettings',
          detailsJson: { keys: input.settings.map((s) => s.key) },
          ipAddress: ctx.ip,
          userAgent: ctx.userAgent,
        },
      })

      return results
    }),

  /**
   * Get all categories
   */
  getCategories: adminProcedure.query(async ({ ctx }) => {
    const settings = await ctx.prisma.systemSettings.findMany({
      select: { category: true },
      distinct: ['category'],
    })

    return settings.map((s) => s.category)
  }),

  /**
   * Test AI connection
   */
  testAIConnection: superAdminProcedure.mutation(async ({ ctx }) => {
    const apiKeySetting = await ctx.prisma.systemSettings.findUnique({
      where: { key: 'openai_api_key' },
    })

    if (!apiKeySetting?.value) {
      return { success: false, error: 'API key not configured' }
    }

    try {
      // Test OpenAI connection with a minimal request
      const response = await fetch('https://api.openai.com/v1/models', {
        headers: {
          Authorization: `Bearer ${apiKeySetting.value}`,
        },
      })

      if (response.ok) {
        return { success: true }
      } else {
        const error = await response.json()
        return { success: false, error: error.error?.message || 'Unknown error' }
      }
    } catch (error) {
      return { success: false, error: 'Connection failed' }
    }
  }),

  /**
   * Test email connection
   */
  testEmailConnection: superAdminProcedure
    .input(z.object({ testEmail: z.string().email() }))
    .mutation(async ({ ctx, input }) => {
      try {
        const { sendTestEmail } = await import('@/lib/email')
        const success = await sendTestEmail(input.testEmail)
        return { success, error: success ? null : 'Failed to send test email' }
      } catch (error) {
        return { success: false, error: 'Email configuration error' }
      }
    }),

  /**
   * Get WhatsApp settings status
   */
  getWhatsAppStatus: adminProcedure.query(async ({ ctx }) => {
    const [enabledSetting, providerSetting] = await Promise.all([
      ctx.prisma.systemSettings.findUnique({
        where: { key: 'whatsapp_enabled' },
      }),
      ctx.prisma.systemSettings.findUnique({
        where: { key: 'whatsapp_provider' },
      }),
    ])

    return {
      enabled: enabledSetting?.value === 'true',
      provider: providerSetting?.value || 'META',
    }
  }),

  /**
   * Test WhatsApp connection
   */
  testWhatsAppConnection: superAdminProcedure.mutation(async () => {
    const provider = await getWhatsAppProvider()

    if (!provider) {
      return { success: false, error: 'WhatsApp not configured' }
    }

    const result = await provider.testConnection()
    const providerType = await getWhatsAppProviderType()

    return {
      ...result,
      provider: providerType,
    }
  }),

  /**
   * Send a test WhatsApp message
   */
  sendTestWhatsApp: superAdminProcedure
    .input(z.object({ phoneNumber: z.string() }))
    .mutation(async ({ input }) => {
      const provider = await getWhatsAppProvider()

      if (!provider) {
        return { success: false, error: 'WhatsApp not configured' }
      }

      return provider.sendText(
        input.phoneNumber,
        'This is a test message from MOPC Platform.'
      )
    }),

  /**
   * Update user notification preferences
   */
  updateNotificationPreferences: protectedProcedure
    .input(
      z.object({
        phoneNumber: z.string().optional().nullable(),
        notificationPreference: z.enum(['EMAIL', 'WHATSAPP', 'BOTH', 'NONE']),
        whatsappOptIn: z.boolean(),
      })
    )
    .mutation(async ({ ctx, input }) => {
      const user = await ctx.prisma.user.update({
        where: { id: ctx.user.id },
        data: {
          phoneNumber: input.phoneNumber,
          notificationPreference: input.notificationPreference,
          whatsappOptIn: input.whatsappOptIn,
        },
      })

      // Audit log
      await ctx.prisma.auditLog.create({
        data: {
          userId: ctx.user.id,
          action: 'UPDATE_NOTIFICATION_PREFERENCES',
          entityType: 'User',
          entityId: ctx.user.id,
          detailsJson: {
            notificationPreference: input.notificationPreference,
            whatsappOptIn: input.whatsappOptIn,
          },
          ipAddress: ctx.ip,
          userAgent: ctx.userAgent,
        },
      })

      return user
    }),

  /**
   * Get notification statistics (admin only)
   */
  getNotificationStats: adminProcedure
    .input(
      z.object({
        startDate: z.string().datetime().optional(),
        endDate: z.string().datetime().optional(),
      })
    )
    .query(async ({ ctx, input }) => {
      const where: Record<string, unknown> = {}

      if (input.startDate || input.endDate) {
        where.createdAt = {}
        if (input.startDate) {
          (where.createdAt as Record<string, Date>).gte = new Date(input.startDate)
        }
        if (input.endDate) {
          (where.createdAt as Record<string, Date>).lte = new Date(input.endDate)
        }
      }

      const [total, byChannel, byStatus, byType] = await Promise.all([
        ctx.prisma.notificationLog.count({ where }),
        ctx.prisma.notificationLog.groupBy({
          by: ['channel'],
          where,
          _count: true,
        }),
        ctx.prisma.notificationLog.groupBy({
          by: ['status'],
          where,
          _count: true,
        }),
        ctx.prisma.notificationLog.groupBy({
          by: ['type'],
          where,
          _count: true,
        }),
      ])

      return {
        total,
        byChannel: Object.fromEntries(
          byChannel.map((r) => [r.channel, r._count])
        ),
        byStatus: Object.fromEntries(
          byStatus.map((r) => [r.status, r._count])
        ),
        byType: Object.fromEntries(
          byType.map((r) => [r.type, r._count])
        ),
      }
    }),
})
