/**
 * User preferences query helpers — dark-light-theme (spec 114).
 *
 * Provides audited write + unaudited read for the ui_theme column.
 * The UPDATE is tenant-scoped and runs inside a transaction with an
 * audit_log row (require-audit-in-transaction).
 *
 * Routes must NOT import schema tables directly — use these helpers.
 */
import { and, eq } from 'drizzle-orm'
import type { TenantId, UserId } from '@zync/types'
import type { Db } from '../client'
import { userPreferences } from '../schema'
import { auditLog } from './_audit-forward'

export type UiTheme = 'dark' | 'light' | 'system'
export type UiShell = 'classic' | 'os'

export async function setUserShell(db: Db, userId: UserId, tenantId: TenantId, uiShell: UiShell): Promise<void> {
  await db.transaction(async (tx) => {
    await tx.insert(userPreferences).values({ userId, tenantId, uiShell })
      .onConflictDoUpdate({ target: [userPreferences.userId, userPreferences.tenantId], set: { uiShell, updatedAt: new Date() } })
    await tx.insert(auditLog).values({ tenantId, actorId: userId, actorType: 'user', entityType: 'user_preferences', entityId: userId, action: 'user_preferences.ui_shell.updated', changes: { ui_shell: [null, uiShell] } })
  })
}

/**
 * Read the stored ui_theme for a (user, tenant) pair.
 * Returns 'dark' when no row exists or the column is null.
 */
export async function getUserTheme(
  db: Db,
  userId: UserId,
  tenantId: TenantId,
): Promise<UiTheme> {
  const [row] = await db
    .select({ uiTheme: userPreferences.uiTheme })
    .from(userPreferences)
    .where(and(eq(userPreferences.userId, userId), eq(userPreferences.tenantId, tenantId)))
    .limit(1)

  return (row?.uiTheme as UiTheme | null | undefined) ?? 'dark'
}

/**
 * Update ui_theme for (user, tenant) and write an audit log row in the same
 * transaction. Upserts the preferences row if it does not yet exist.
 */
export async function setUserTheme(
  db: Db,
  args: {
    userId: UserId
    tenantId: TenantId
    uiTheme: UiTheme
    actorIp?: string | null
    requestId?: string | null
  },
): Promise<void> {
  await db.transaction(async (tx) => {
    await tx
      .insert(userPreferences)
      .values({
        userId: args.userId,
        tenantId: args.tenantId,
        uiTheme: args.uiTheme,
      })
      .onConflictDoUpdate({
        target: [userPreferences.userId, userPreferences.tenantId],
        set: { uiTheme: args.uiTheme, updatedAt: new Date() },
      })

    await tx.insert(auditLog).values({
      tenantId: args.tenantId,
      actorId: args.userId,
      actorType: 'user',
      entityType: 'user_preferences',
      entityId: args.userId,
      action: 'user_preferences.ui_theme.updated',
      changes: { ui_theme: [null, args.uiTheme] },
      ip: args.actorIp ?? null,
      requestId: args.requestId ?? null,
    })
  })
}
