import { SignJWT, jwtVerify } from 'jose'
import { cookies } from 'next/headers'
import { scrypt, randomBytes, timingSafeEqual } from 'crypto'
import { db } from '@/lib/db'

const SESSION_SECRET = new TextEncoder().encode(
  process.env.SESSION_SECRET || 'eorg-fallback-secret-change-me-in-production',
)

export const COOKIE_NAME = 'eorg_session'

// When BYPASS_AUTH=true we treat every request as the first user in the DB.
// Useful for single-user mode during early use; flip it off to re-enable login.
const BYPASS_AUTH = process.env.BYPASS_AUTH === 'true'

export interface SessionPayload {
  userId: string
  email: string
  name: string
}

// Cached bypass session — first user lookup is memoized for the life of the
// process so we don't hit the DB on every page render when BYPASS_AUTH is on.
let bypassCache: SessionPayload | null = null
async function getBypassSession(): Promise<SessionPayload | null> {
  if (bypassCache) return bypassCache
  const user = await db.user.findFirst({
    orderBy: { createdAt: 'asc' },
    select: { id: true, email: true, name: true },
  })
  if (!user) return null
  bypassCache = { userId: user.id, email: user.email, name: user.name }
  return bypassCache
}

export async function hashPassword(password: string): Promise<string> {
  const salt = randomBytes(16).toString('hex')
  return new Promise((resolve, reject) => {
    scrypt(password, salt, 64, (err, derivedKey) => {
      if (err) return reject(err)
      resolve(`${salt}:${derivedKey.toString('hex')}`)
    })
  })
}

export async function verifyPassword(password: string, hash: string): Promise<boolean> {
  const [salt, key] = hash.split(':')
  if (!salt || !key) return false
  return new Promise((resolve, reject) => {
    scrypt(password, salt, 64, (err, derivedKey) => {
      if (err) return reject(err)
      const stored = Buffer.from(key, 'hex')
      if (stored.length !== derivedKey.length) return resolve(false)
      resolve(timingSafeEqual(stored, derivedKey))
    })
  })
}

export async function createSessionToken(payload: SessionPayload): Promise<string> {
  return await new SignJWT({ ...payload })
    .setProtectedHeader({ alg: 'HS256' })
    .setIssuedAt()
    .setExpirationTime('30d')
    .sign(SESSION_SECRET)
}

export const SESSION_COOKIE_OPTIONS = {
  httpOnly: true,
  secure: process.env.SECURE_COOKIES === 'true',
  sameSite: 'lax' as const,
  maxAge: 60 * 60 * 24 * 30,
  path: '/',
}

export async function createSession(payload: SessionPayload) {
  const token = await createSessionToken(payload)
  const cookieStore = await cookies()
  cookieStore.set(COOKIE_NAME, token, SESSION_COOKIE_OPTIONS)
}

export async function getSession(): Promise<SessionPayload | null> {
  if (BYPASS_AUTH) return getBypassSession()
  const cookieStore = await cookies()
  const token = cookieStore.get(COOKIE_NAME)?.value
  if (!token) return null
  try {
    const { payload } = await jwtVerify(token, SESSION_SECRET)
    return payload as unknown as SessionPayload
  } catch {
    return null
  }
}

export async function destroySession() {
  const cookieStore = await cookies()
  cookieStore.delete(COOKIE_NAME)
}

export async function requireSession(): Promise<SessionPayload> {
  const session = await getSession()
  if (!session) throw new Error('Unauthorized')
  return session
}
