// Generic API error helpers — keep internal SQL / table / constraint
// detail server-side, hand the client a stable shape.
//
// Usage:
//   import { sanitizeApiError, errorResponse } from '@/lib/api/error'
//
//   const { data, error } = await supabase.from('projects').insert(...)
//   if (error) {
//     return errorResponse('projects.insert_failed', error)
//   }
//
// The logger receives the full error context (incl. error.message,
// error.code, error.details). The HTTP response receives:
//   { error: 'projects.insert_failed', message: 'A database error occurred.' }
//
// Why
//   Supabase's PostgREST surfaces table names, constraint names, and SQL
//   in `error.message`. That is information disclosure (mo2 finding P1-6).
//   Generic codes preserve actionability for the client (which knows the
//   code-vocabulary) without leaking schema.

import { NextResponse } from 'next/server'
import { logger } from '@/lib/logger'

export type ApiErrorCode =
  | 'unauthorized'
  | 'forbidden'
  | 'not_found'
  | 'invalid_body'
  | 'conflict'
  | 'rate_limited'
  | 'internal_error'
  | (string & { _brand?: 'route_specific' })

export type SanitizedError = {
  error: ApiErrorCode
  message: string
}

const GENERIC_MESSAGES: Record<string, string> = {
  unauthorized:    'Authentication required.',
  forbidden:       'Insufficient permissions for this operation.',
  not_found:       'The requested resource was not found.',
  invalid_body:    'Request body did not match the expected schema.',
  conflict:        'The resource has been modified concurrently. Reload and retry.',
  rate_limited:    'Too many requests. Try again later.',
  internal_error:  'A server error occurred. The incident has been logged.',
}

const DEFAULT_GENERIC_MESSAGE = 'An unexpected error occurred.'

export function sanitizeApiError(
  code: ApiErrorCode,
  detail?: unknown,
): SanitizedError {
  const message = GENERIC_MESSAGES[code] ?? DEFAULT_GENERIC_MESSAGE
  if (detail !== undefined) {
    logger.error(`api.error.${code}`, detail, { code })
  }
  return { error: code, message }
}

export function errorResponse(
  code: ApiErrorCode,
  detail?: unknown,
  status = 500,
): NextResponse {
  return NextResponse.json(sanitizeApiError(code, detail), { status })
}

// Status-code helpers for the most common cases.
export const apiError = {
  unauthorized:   (d?: unknown) => errorResponse('unauthorized', d, 401),
  forbidden:      (d?: unknown) => errorResponse('forbidden',    d, 403),
  notFound:       (d?: unknown) => errorResponse('not_found',    d, 404),
  invalidBody:    (issues?: unknown) =>
    NextResponse.json(
      { error: 'invalid_body', message: GENERIC_MESSAGES.invalid_body, issues },
      { status: 400 },
    ),
  conflict:       (d?: unknown) => errorResponse('conflict',     d, 409),
  rateLimited:    (d?: unknown) => errorResponse('rate_limited', d, 429),
  internalError:  (d?: unknown) => errorResponse('internal_error', d, 500),
}

/**
 * Route-level internal-error helper with a custom public message.
 *
 * Logs the raw error detail server-side (via logger) and returns a JSON
 * response that exposes ONLY the caller-supplied `publicMessage` — never
 * the raw Supabase / constraint / SQL detail.
 *
 * Usage in route handlers:
 *   if (error) return routeError('Benutzer konnte nicht aktualisiert werden.', error)
 */
export function routeError(
  publicMessage: string,
  detail?: unknown,
  status = 500,
): NextResponse {
  if (detail !== undefined) {
    logger.error('api.route.internal_error', detail, { publicMessage })
  }
  return NextResponse.json(
    { error: 'internal_error', message: publicMessage },
    { status },
  )
}
