import crypto from 'node:crypto';

export const nowSeconds = () => Math.floor(Date.now() / 1000);
export const nowIso = () => new Date().toISOString();
export const uuid = () => crypto.randomUUID();
export const base64url = (value) => Buffer.from(value).toString('base64url');
export const fromBase64url = (value) => Buffer.from(value, 'base64url').toString('utf8');
export const sha256 = (value) => crypto.createHash('sha256').update(String(value)).digest('hex');
export const hmac = (secret, value) => crypto.createHmac('sha256', secret).update(String(value)).digest('base64url');
export const safeEqual = (a, b) => {
  const left = Buffer.from(String(a));
  const right = Buffer.from(String(b));
  return left.length === right.length && crypto.timingSafeEqual(left, right);
};

export function clampInt(value, min, max, fallback = min) {
  const n = Number.parseInt(value, 10);
  if (!Number.isFinite(n)) return fallback;
  return Math.max(min, Math.min(max, n));
}

export function parseJson(value, fallback = null) {
  try { return JSON.parse(value); } catch { return fallback; }
}

export function sanitizeText(value, max = 120) {
  return String(value ?? '')
    .replace(/[\u0000-\u001f\u007f]/g, '')
    .trim()
    .slice(0, max);
}

export function dayKey(date = new Date()) {
  return date.toISOString().slice(0, 10);
}

export function periodKey(repeatType, date = new Date()) {
  if (repeatType === 'once') return 'once';
  if (repeatType === 'weekly') {
    const copy = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
    const day = copy.getUTCDay() || 7;
    copy.setUTCDate(copy.getUTCDate() + 4 - day);
    const yearStart = new Date(Date.UTC(copy.getUTCFullYear(), 0, 1));
    const week = Math.ceil((((copy - yearStart) / 86400000) + 1) / 7);
    return `${copy.getUTCFullYear()}-W${String(week).padStart(2, '0')}`;
  }
  return dayKey(date);
}

export function weightedPick(items) {
  const enabled = items.filter((item) => item.enabled && item.weight > 0);
  const total = enabled.reduce((sum, item) => sum + item.weight, 0);
  if (total <= 0) throw new Error('No enabled wheel segment.');
  const target = crypto.randomInt(1, total + 1);
  let cursor = 0;
  for (const item of enabled) {
    cursor += item.weight;
    if (target <= cursor) return item;
  }
  return enabled.at(-1);
}
