import type { ZodType } from "zod";

/** Applikationsfel med HTTP-status och maskinläsbar kod. */
export class ApiError extends Error {
  constructor(
    public readonly statusCode: number,
    public readonly code: string,
    message: string,
    public readonly details?: unknown,
  ) {
    super(message);
    this.name = "ApiError";
  }
}

export const errors = {
  badRequest: (msg: string, details?: unknown) => new ApiError(400, "BAD_REQUEST", msg, details),
  unauthorized: (msg = "Ogiltig eller saknad autentisering") =>
    new ApiError(401, "UNAUTHORIZED", msg),
  forbidden: (msg = "Åtkomst nekad") => new ApiError(403, "FORBIDDEN", msg),
  notFound: (msg = "Resursen finns inte") => new ApiError(404, "NOT_FOUND", msg),
  conflict: (msg: string) => new ApiError(409, "CONFLICT", msg),
  quotaExceeded: (msg: string) => new ApiError(429, "QUOTA_EXCEEDED", msg),
  paymentRequired: (msg: string) => new ApiError(402, "PREMIUM_REQUIRED", msg),
  internal: (msg = "Internt fel") => new ApiError(500, "INTERNAL", msg),
};

/**
 * Validera indata mot ett Zod-schema. Kastar 400 med detaljer vid fel.
 * Medvetet vald i stället för type-provider: färre rörliga delar i
 * major-versionsgränser, samma säkerhet (se docs/beslutslogg.md D-011).
 */
export function parse<T>(schema: ZodType<T>, data: unknown, what = "indata"): T {
  const result = schema.safeParse(data);
  if (!result.success) {
    throw new ApiError(400, "VALIDATION_ERROR", `Ogiltig ${what}`, result.error.issues);
  }
  return result.data;
}
