import { getAuthUserId } from '@convex-dev/auth/server';
import { ConvexError } from 'convex/values';

import type { Doc, Id } from './_generated/dataModel';
import type { MutationCtx, QueryCtx } from './_generated/server';

type Ctx = QueryCtx | MutationCtx;

export const getRequiredUserId = async (ctx: Ctx): Promise<Id<'users'>> => {
  const userId = await getAuthUserId(ctx);
  if (!userId) throw new ConvexError('Not authenticated.');
  return userId;
};

export const getOwnedSpoon = async (
  ctx: Ctx,
  spoonId: Id<'spoons'>,
  ownerId: Id<'users'>,
): Promise<Doc<'spoons'>> => {
  const spoon = await ctx.db.get(spoonId);
  if (spoon?.ownerId !== ownerId) {
    throw new ConvexError('Spoon not found.');
  }
  return spoon;
};

export const requireText = (value: string, label: string): string => {
  const trimmed = value.trim();
  if (!trimmed) throw new ConvexError(`${label} is required.`);
  return trimmed;
};

export const optionalText = (value: string | undefined) => {
  const trimmed = value?.trim();
  if (!trimmed) return undefined;
  return trimmed;
};

// Linux username for the per-user container home (/home/<username>). Derived
// from the first token of the profile name, sanitized; falls back to "user".
export const deriveHomeUsername = (name?: string): string => {
  const first = (name ?? '').trim().split(/\s+/)[0] ?? '';
  const sanitized = first.toLowerCase().replace(/[^a-z0-9_-]/g, '');
  return sanitized || 'user';
};

// Normalizes a dotfile path to a safe HOME-relative path (no leading slash, no
// "..", no empty segments). Throws on anything that would escape HOME.
export const normalizeDotfilePath = (rawPath: string): string => {
  const cleaned = rawPath
    .trim()
    .replace(/^\.\/+/, '')
    .replace(/^\/+/, '');
  const segments = cleaned.split('/').filter((s) => s.length > 0);
  if (segments.length === 0) {
    throw new ConvexError('A dotfile path is required.');
  }
  if (segments.some((s) => s === '..' || s === '.')) {
    throw new ConvexError(`Invalid dotfile path: ${rawPath}`);
  }
  return segments.join('/');
};
