import type { RowDataPacket, ResultSetHeader } from 'mysql2'
import { randomUUID } from 'crypto'
import { getPool } from '@/lib/db'

export type DbUser = {
  id: string
  email: string
  emailVerified: Date | null
  name: string | null
  password: string
  termsAcceptedAt: Date
  createdAt: Date
  updatedAt: Date
}

type UserRow = RowDataPacket & {
  id: string
  email: string
  email_verified: Date | null
  name: string | null
  password: string
  terms_accepted_at: Date
  created_at: Date
  updated_at: Date
}

function mapRow(row: UserRow): DbUser {
  return {
    id: row.id,
    email: row.email,
    emailVerified: row.email_verified,
    name: row.name,
    password: row.password,
    termsAcceptedAt: row.terms_accepted_at,
    createdAt: row.created_at,
    updatedAt: row.updated_at,
  }
}

export async function findUserByEmail(email: string): Promise<DbUser | null> {
  const normalized = email.trim().toLowerCase()
  const [rows] = await getPool().query<UserRow[]>(
    `SELECT id, email, email_verified, name, password, terms_accepted_at, created_at, updated_at
     FROM users WHERE email = ? LIMIT 1`,
    [normalized],
  )
  const row = rows[0]
  return row ? mapRow(row) : null
}

export async function createUser(input: {
  email: string
  passwordHash: string
  name: string | null
  termsAcceptedAt: Date
}): Promise<{ id: string }> {
  const id = randomUUID()
  const email = input.email.trim().toLowerCase()

  const [result] = await getPool().execute<ResultSetHeader>(
    `INSERT INTO users (id, email, email_verified, name, password, terms_accepted_at)
     VALUES (?, ?, NULL, ?, ?, ?)`,
    [id, email, input.name, input.passwordHash, input.termsAcceptedAt],
  )

  if (result.affectedRows !== 1) {
    throw new Error('Nie udało się zapisać użytkownika.')
  }

  return { id }
}

export async function emailExists(email: string): Promise<boolean> {
  const normalized = email.trim().toLowerCase()
  const [rows] = await getPool().query<RowDataPacket[]>(
    'SELECT 1 AS ok FROM users WHERE email = ? LIMIT 1',
    [normalized],
  )
  return rows.length > 0
}
