import bcrypt from 'bcryptjs';
import jwt, { type SignOptions } from 'jsonwebtoken';
import crypto from 'node:crypto';
import type { AuthUser, Role } from './types.js';
import { config } from './config.js';

export interface TokenPayload {
  sub: string;
  role: Role;
  tokenVersion: number;
  kind: 'access' | 'refresh';
}

export async function hashPassword(password: string) {
  return bcrypt.hash(password, 12);
}

export async function comparePassword(password: string, hash: string) {
  return bcrypt.compare(password, hash);
}

export function passwordPolicyError(password: string): string | null {
  if (password.length < 12) return 'Password must contain at least 12 characters.';
  if (!/[A-Z]/.test(password)) return 'Password must include an uppercase letter.';
  if (!/[a-z]/.test(password)) return 'Password must include a lowercase letter.';
  if (!/[0-9]/.test(password)) return 'Password must include a number.';
  if (!/[^A-Za-z0-9]/.test(password)) return 'Password must include a special character.';
  return null;
}

function sign(payload: TokenPayload, secret: string, expiresIn: string) {
  return jwt.sign(payload, secret, { expiresIn } as SignOptions);
}

export function issueAccessToken(user: AuthUser, tokenVersion: number) {
  return sign({ sub: user.id, role: user.role, tokenVersion, kind: 'access' }, config.jwtAccessSecret, config.accessTokenTtl);
}

export function issueRefreshToken(user: AuthUser, tokenVersion: number) {
  return sign({ sub: user.id, role: user.role, tokenVersion, kind: 'refresh' }, config.jwtRefreshSecret, config.refreshTokenTtl);
}

export function verifyAccessToken(token: string): TokenPayload {
  const payload = jwt.verify(token, config.jwtAccessSecret) as TokenPayload;
  if (payload.kind !== 'access') throw new Error('Invalid access token');
  return payload;
}

export function verifyRefreshToken(token: string): TokenPayload {
  const payload = jwt.verify(token, config.jwtRefreshSecret) as TokenPayload;
  if (payload.kind !== 'refresh') throw new Error('Invalid refresh token');
  return payload;
}

export function tokenHash(token: string) {
  return crypto.createHash('sha256').update(token).digest('hex');
}

export function randomToken() {
  return crypto.randomBytes(32).toString('base64url');
}

export function publicUser(row: Record<string, unknown>): AuthUser {
  return {
    id: String(row.id),
    name: String(row.name),
    email: String(row.email),
    phone: row.phone ? String(row.phone) : null,
    role: String(row.role) as Role,
    forcePasswordChange: Boolean(row.force_password_change),
    employeeCode: row.employee_code ? String(row.employee_code) : null
  };
}
