import type {User} from '@crumbs/core/db'
import {generateHandle} from '@crumbs/core/names'
import type {PublicUser} from '@crumbs/core/schemas'
import {eq} from 'drizzle-orm'

import {db, schema} from '../db/client'
import {publicImageUrl} from '../lib/source-image'
import {isUniqueViolation} from '../lib/sql'

const HANDLE_ATTEMPTS = 12

export const upsertUserByEmail = async (
  email: string,
): Promise<User> => {
  const normalized = email.trim().toLowerCase()

  for (let attempt = 0; attempt < HANDLE_ATTEMPTS; attempt++) {
    const handle =
      attempt === 0
        ? generateHandle()
        : `${generateHandle()}-${Math.floor(Math.random() * 1000)}`
    try {
      const [user] = await db
        .insert(schema.users)
        .values({email: normalized, handle})
        .onConflictDoNothing({target: schema.users.email})
        .returning()
      if (user) return user
      // email already taken -> existing user, handle untouched
      const [existing] = await db
        .select()
        .from(schema.users)
        .where(eq(schema.users.email, normalized))
        .limit(1)
      if (existing) return existing
    } catch (err) {
      if (isUniqueViolation(err)) continue // handle collision, retry
      throw err
    }
  }

  throw new Error('could not allocate a unique handle')
}

export const toPublicUser = (user: User): PublicUser => ({
  id: user.id,
  email: user.email,
  handle: user.handle,
  avatarUrl: publicImageUrl(user.avatarRef),
  createdAt: user.createdAt.toISOString(),
})
