/**
 * Device Token Query Functions
 * CRUD operations for push notification device tokens
 */

import { useDB, eq } from '../../utils/database'
import { deviceTokens, type DeviceToken } from '../schema'

export type Platform = 'android' | 'ios' | 'web'

/**
 * Get all device tokens for a user
 */
export async function getUserDeviceTokens(userId: string): Promise<DeviceToken[]> {
  try {
    const db = useDB()
    const tokens = await db
      .select()
      .from(deviceTokens)
      .where(eq(deviceTokens.userId, userId))

    return tokens
  } catch (error) {
    console.error('[getUserDeviceTokens]', userId, error)
    throw createError({
      statusCode: 500,
      statusMessage: 'Failed to get device tokens'
    })
  }
}

/**
 * Get device token by token string
 */
export async function getDeviceTokenByToken(token: string): Promise<DeviceToken | null> {
  try {
    const db = useDB()
    const [result] = await db
      .select()
      .from(deviceTokens)
      .where(eq(deviceTokens.token, token))
      .limit(1)

    return result || null
  } catch (error) {
    console.error('[getDeviceTokenByToken]', error)
    throw createError({
      statusCode: 500,
      statusMessage: 'Failed to get device token'
    })
  }
}

/**
 * Register a new device token (or update if exists)
 */
export async function registerDeviceToken(
  userId: string,
  token: string,
  platform: Platform,
  deviceId?: string
): Promise<DeviceToken> {
  try {
    const db = useDB()

    // Check if token already exists
    const existing = await getDeviceTokenByToken(token)

    if (existing) {
      // Update existing token with new userId if different
      if (existing.userId !== userId) {
        const [updated] = await db
          .update(deviceTokens)
          .set({
            userId,
            platform,
            deviceId,
            updatedAt: new Date()
          })
          .where(eq(deviceTokens.id, existing.id))
          .returning()

        return updated!
      }
      return existing
    }

    // Insert new token
    const [newToken] = await db
      .insert(deviceTokens)
      .values({
        userId,
        token,
        platform,
        deviceId
      })
      .returning()

    if (!newToken) {
      throw new Error('Failed to register device token')
    }

    return newToken
  } catch (error) {
    console.error('[registerDeviceToken]', userId, platform, error)
    throw createError({
      statusCode: 500,
      statusMessage: 'Failed to register device token'
    })
  }
}

/**
 * Remove a device token
 */
export async function removeDeviceToken(token: string): Promise<boolean> {
  try {
    const db = useDB()
    const result = await db
      .delete(deviceTokens)
      .where(eq(deviceTokens.token, token))
      .returning()

    return result.length > 0
  } catch (error) {
    console.error('[removeDeviceToken]', error)
    throw createError({
      statusCode: 500,
      statusMessage: 'Failed to remove device token'
    })
  }
}

/**
 * Remove all device tokens for a user
 */
export async function removeUserDeviceTokens(userId: string): Promise<number> {
  try {
    const db = useDB()
    const result = await db
      .delete(deviceTokens)
      .where(eq(deviceTokens.userId, userId))
      .returning()

    return result.length
  } catch (error) {
    console.error('[removeUserDeviceTokens]', userId, error)
    throw createError({
      statusCode: 500,
      statusMessage: 'Failed to remove user device tokens'
    })
  }
}

/**
 * Get all users with device tokens (for bulk notifications)
 */
export async function getAllUsersWithTokens(): Promise<{ userId: string, tokens: string[] }[]> {
  try {
    const db = useDB()
    const allTokens = await db
      .select()
      .from(deviceTokens)

    // Group by userId
    const userTokenMap = new Map<string, string[]>()
    for (const token of allTokens) {
      const tokens = userTokenMap.get(token.userId) || []
      tokens.push(token.token)
      userTokenMap.set(token.userId, tokens)
    }

    return Array.from(userTokenMap.entries()).map(([userId, tokens]) => ({
      userId,
      tokens
    }))
  } catch (error) {
    console.error('[getAllUsersWithTokens]', error)
    throw createError({
      statusCode: 500,
      statusMessage: 'Failed to get users with tokens'
    })
  }
}
