import { z } from 'zod'
import { router, adminProcedure, superAdminProcedure, protectedProcedure } from '../trpc'
import { getWhatsAppProvider, getWhatsAppProviderType } from '@/lib/whatsapp'
import { listAvailableModels, testOpenAIConnection, isReasoningModel } from '@/lib/openai'
import { getAIUsageStats, getCurrentMonthCost, formatCost } from '@/server/utils/ai-usage'

/**
 * Categorize an OpenAI model for display
 */
function categorizeModel(modelId: string): string {
  const id = modelId.toLowerCase()
  // GPT-5+ series (newest models)
  if (id.startsWith('gpt-5') || id.startsWith('gpt-6') || id.startsWith('gpt-7')) return 'gpt-5+'
  if (id.startsWith('gpt-4o')) return 'gpt-4o'
  if (id.startsWith('gpt-4')) return 'gpt-4'
  if (id.startsWith('gpt-3.5')) return 'gpt-3.5'
  if (id.startsWith('o1') || id.startsWith('o3') || id.startsWith('o4')) return 'reasoning'
  return 'other'
}

export const settingsRouter = router({
  /**
   * Get public feature flags (no auth required)
   * These are non-sensitive settings that can be exposed to any user
   */
  getFeatureFlags: protectedProcedure.query(async ({ ctx }) => {
    const [whatsappEnabled] = await Promise.all([
      ctx.prisma.systemSettings.findUnique({
        where: { key: 'whatsapp_enabled' },
      }),
    ])

    return {
      whatsappEnabled: whatsappEnabled?.value === 'true',
    }
  }),

  /**
   * 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 with the configured model
   */
  testAIConnection: superAdminProcedure.mutation(async () => {
    const result = await testOpenAIConnection()
    return result
  }),

  /**
   * List available AI models from OpenAI
   */
  listAIModels: superAdminProcedure.query(async () => {
    const result = await listAvailableModels()

    if (!result.success || !result.models) {
      return {
        success: false,
        error: result.error || 'Failed to fetch models',
        models: [],
      }
    }

    // Categorize and annotate models
    const categorizedModels = result.models.map(model => ({
      id: model,
      name: model,
      isReasoning: isReasoningModel(model),
      category: categorizeModel(model),
    }))

    // Sort: GPT-5+ first, then GPT-4o, then other GPT-4, then GPT-3.5, then reasoning models
    const sorted = categorizedModels.sort((a, b) => {
      const order = ['gpt-5+', 'gpt-4o', 'gpt-4', 'gpt-3.5', 'reasoning', 'other']
      const aOrder = order.findIndex(cat => a.category === cat)
      const bOrder = order.findIndex(cat => b.category === cat)
      if (aOrder !== bOrder) return aOrder - bOrder
      return a.id.localeCompare(b.id)
    })

    return {
      success: true,
      models: sorted,
    }
  }),

  /**
   * 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])
        ),
      }
    }),

  /**
   * Get AI usage statistics (admin only)
   */
  getAIUsageStats: adminProcedure
    .input(
      z.object({
        startDate: z.string().datetime().optional(),
        endDate: z.string().datetime().optional(),
      })
    )
    .query(async ({ input }) => {
      const startDate = input.startDate ? new Date(input.startDate) : undefined
      const endDate = input.endDate ? new Date(input.endDate) : undefined

      const stats = await getAIUsageStats(startDate, endDate)

      return {
        totalTokens: stats.totalTokens,
        totalCost: stats.totalCost,
        totalCostFormatted: formatCost(stats.totalCost),
        byAction: Object.fromEntries(
          Object.entries(stats.byAction).map(([action, data]) => [
            action,
            {
              ...data,
              costFormatted: formatCost(data.cost),
            },
          ])
        ),
        byModel: Object.fromEntries(
          Object.entries(stats.byModel).map(([model, data]) => [
            model,
            {
              ...data,
              costFormatted: formatCost(data.cost),
            },
          ])
        ),
      }
    }),

  /**
   * Get current month AI usage cost (admin only)
   */
  getAICurrentMonthCost: adminProcedure.query(async () => {
    const { cost, tokens, requestCount } = await getCurrentMonthCost()

    return {
      cost,
      costFormatted: formatCost(cost),
      tokens,
      requestCount,
    }
  }),

  /**
   * Get AI usage history (last 30 days grouped by day)
   */
  getAIUsageHistory: adminProcedure
    .input(
      z.object({
        days: z.number().min(1).max(90).default(30),
      })
    )
    .query(async ({ ctx, input }) => {
      const startDate = new Date()
      startDate.setDate(startDate.getDate() - input.days)
      startDate.setHours(0, 0, 0, 0)

      const logs = await ctx.prisma.aIUsageLog.findMany({
        where: {
          createdAt: { gte: startDate },
        },
        select: {
          createdAt: true,
          totalTokens: true,
          estimatedCostUsd: true,
          action: true,
        },
        orderBy: { createdAt: 'asc' },
      })

      // Group by day
      const dailyData: Record<string, { date: string; tokens: number; cost: number; count: number }> = {}

      for (const log of logs) {
        const dateKey = log.createdAt.toISOString().split('T')[0]
        if (!dailyData[dateKey]) {
          dailyData[dateKey] = { date: dateKey, tokens: 0, cost: 0, count: 0 }
        }
        dailyData[dateKey].tokens += log.totalTokens
        dailyData[dateKey].cost += log.estimatedCostUsd?.toNumber() ?? 0
        dailyData[dateKey].count += 1
      }

      return Object.values(dailyData).map((day) => ({
        ...day,
        costFormatted: formatCost(day.cost),
      }))
    }),
})
