import 'server-only';
import crypto from 'node:crypto';
import bcrypt from 'bcryptjs';
import { cookies } from 'next/headers';
import { db } from './db';

export const SESSION_COOKIE = 'dk-session';
const SESSION_TTL_MS = 1000 * 60 * 60 * 24 * 30; // 30 days

export type User = {
  id: number;
  email: string;
  first: string;
  last: string;
  account: 'client' | 'pro';
  business_name: string;
  business_category: string;
  business_address: string;
  business_desc: string;
  city: string;
  phone: string;
  avatar: string;
  notif_prefs: string;
};

type UserRow = User & { password_hash: string; created_at: number };

export function hashPassword(pw: string): string {
  return bcrypt.hashSync(pw, 10);
}
export function verifyPassword(pw: string, hash: string): boolean {
  return bcrypt.compareSync(pw, hash);
}

export function findUserByEmail(email: string): UserRow | undefined {
  return db.prepare('SELECT * FROM users WHERE email = ?').get(email.toLowerCase()) as
    | UserRow
    | undefined;
}

export function createUser(input: {
  email: string;
  password: string;
  first: string;
  last: string;
  account: 'client' | 'pro';
  business_name?: string;
}): number {
  const info = db
    .prepare(
      `INSERT INTO users (email, password_hash, first, last, account, business_name, created_at)
       VALUES (@email, @password_hash, @first, @last, @account, @business_name, @created_at)`
    )
    .run({
      email: input.email.toLowerCase(),
      password_hash: hashPassword(input.password),
      first: input.first,
      last: input.last,
      account: input.account,
      business_name: input.business_name ?? '',
      created_at: Date.now(),
    });
  return Number(info.lastInsertRowid);
}

/** Create a session row and set the httpOnly cookie. Call from a server action / route handler. */
export async function startSession(userId: number): Promise<void> {
  const token = crypto.randomBytes(32).toString('hex');
  const now = Date.now();
  db.prepare(
    'INSERT INTO sessions (token, user_id, created_at, expires_at) VALUES (?, ?, ?, ?)'
  ).run(token, userId, now, now + SESSION_TTL_MS);

  const store = await cookies();
  store.set(SESSION_COOKIE, token, {
    httpOnly: true,
    sameSite: 'lax',
    secure: process.env.NODE_ENV === 'production',
    path: '/',
    maxAge: Math.floor(SESSION_TTL_MS / 1000),
  });
}

export async function endSession(): Promise<void> {
  const store = await cookies();
  const token = store.get(SESSION_COOKIE)?.value;
  if (token) db.prepare('DELETE FROM sessions WHERE token = ?').run(token);
  store.delete(SESSION_COOKIE);
}

/** Read the current user from the session cookie. Returns null when logged out. */
export async function getCurrentUser(): Promise<User | null> {
  const store = await cookies();
  const token = store.get(SESSION_COOKIE)?.value;
  if (!token) return null;
  const row = db
    .prepare(
      `SELECT u.id, u.email, u.first, u.last, u.account, u.business_name,
              u.business_category, u.business_address, u.business_desc, u.city, u.phone,
              u.avatar, u.notif_prefs, s.expires_at
       FROM sessions s JOIN users u ON u.id = s.user_id
       WHERE s.token = ?`
    )
    .get(token) as (User & { expires_at: number }) | undefined;
  if (!row) return null;
  if (row.expires_at < Date.now()) {
    db.prepare('DELETE FROM sessions WHERE token = ?').run(token);
    return null;
  }
  const { expires_at, ...user } = row;
  return user;
}
