import bcrypt from 'bcryptjs'
import { Context } from '../types/context'

export interface CreateUserInput {
  email: string
  name: string
  password: string
  role?: 'ADMIN' | 'USER' | 'VIEWER'
}

export interface UpdateUserInput {
  name?: string
  role?: 'ADMIN' | 'USER' | 'VIEWER'
}

interface UserRow {
  id: string
  email: string
  name: string
  role: 'ADMIN' | 'USER' | 'VIEWER'
  created_at: Date
  updated_at: Date
  [key: string]: unknown
}

export async function getUsers(context: Context) {
  const db = context.db
  const result = await db.query(
    'SELECT id, email, name, role, created_at, updated_at FROM users ORDER BY created_at DESC'
  )
  return result.rows.map(mapUser)
}

export async function getUser(context: Context, id: string) {
  const db = context.db
  const result = await db.query(
    'SELECT id, email, name, role, created_at, updated_at FROM users WHERE id = $1',
    [id]
  )

  if (result.rows.length === 0) {
    throw AppErrors.notFound('User', id)
  }

  return mapUser(result.rows[0])
}

export async function createUser(context: Context, input: CreateUserInput) {
  const db = context.db
  const passwordHash = await bcrypt.hash(input.password, 10)

  const result = await db.query(
    `INSERT INTO users (email, name, password_hash, role)
     VALUES ($1, $2, $3, $4)
     RETURNING id, email, name, role, created_at, updated_at`,
    [input.email, input.name, passwordHash, input.role || 'USER']
  )

  return mapUser(result.rows[0])
}

export async function updateUser(context: Context, id: string, input: UpdateUserInput) {
  const db = context.db
  const updates: string[] = []
  const params: unknown[] = []
  let paramCount = 1

  if (input.name !== undefined) {
    updates.push(`name = $${paramCount}`)
    params.push(input.name)
    paramCount++
  }

  if (input.role !== undefined) {
    updates.push(`role = $${paramCount}`)
    params.push(input.role)
    paramCount++
  }

  if (updates.length === 0) {
    return getUser(context, id)
  }

  params.push(id)
  const result = await db.query(
    `UPDATE users SET ${updates.join(', ')} WHERE id = $${paramCount}
     RETURNING id, email, name, role, created_at, updated_at`,
    params
  )

  return mapUser(result.rows[0])
}

export async function deleteUser(context: Context, id: string) {
  const db = context.db
  await db.query('DELETE FROM users WHERE id = $1', [id])
  return true
}

function mapUser(row: UserRow) {
  return {
    id: row.id,
    email: row.email,
    name: row.name,
    role: row.role,
    createdAt: row.created_at,
    updatedAt: row.updated_at,
  }
}

