import { NextResponse } from "next/server";
import {
  ApiSuccessResponse,
  ApiErrorResponse,
  PaginatedResponse,
  ResponseMeta,
  PaginationMeta,
  ApiErrorCode,
} from "./types";

/**
 * API Response Helpers for FitAI Admin API
 *
 * Provides consistent response formatting across all API endpoints.
 */

/**
 * Generate a unique request ID
 */
function generateRequestId(): string {
  return `req_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
}

/**
 * Create response metadata
 */
function createMeta(options?: {
  requestId?: string;
  pagination?: PaginationMeta;
}): ResponseMeta {
  return {
    timestamp: new Date().toISOString(),
    requestId: options?.requestId || generateRequestId(),
    ...(options?.pagination && { pagination: options.pagination }),
  };
}

/**
 * Create a standardized success response
 *
 * @param data - The response data
 * @param options - Optional metadata configuration
 * @returns NextResponse with standardized format
 *
 * @example
 * return successResponse({ user: { id: '123', email: 'user@example.com' } });
 *
 * @example
 * return successResponse({ message: 'User created' }, { status: 201 });
 */
export function successResponse<T>(
  data: T,
  options?: {
    status?: number;
    requestId?: string;
    headers?: HeadersInit;
  },
): NextResponse<ApiSuccessResponse<T>> {
  const response: ApiSuccessResponse<T> = {
    success: true,
    data,
    meta: createMeta({ requestId: options?.requestId }),
  };

  return NextResponse.json(response, {
    status: options?.status || 200,
    headers: options?.headers,
  });
}

/**
 * Create a standardized paginated response
 *
 * @param data - Array of items to return
 * @param pagination - Pagination metadata
 * @param options - Optional configuration
 * @returns NextResponse with paginated format
 *
 * @example
 * const users = await db.getUsers();
 * return paginatedResponse(users, {
 *   page: 1,
 *   pageSize: 20,
 *   totalItems: 100,
 *   totalPages: 5,
 *   hasNextPage: true,
 *   hasPreviousPage: false,
 * });
 */
export function paginatedResponse<T>(
  data: T[],
  pagination: PaginationMeta,
  options?: {
    requestId?: string;
    headers?: HeadersInit;
  },
): NextResponse<PaginatedResponse<T>> {
  const response: PaginatedResponse<T> = {
    success: true,
    data,
    meta: {
      ...createMeta({ requestId: options?.requestId }),
      pagination,
    },
  };

  return NextResponse.json(response, {
    status: 200,
    headers: options?.headers,
  });
}

/**
 * Create a standardized error response
 *
 * @param message - Error message
 * @param options - Error configuration
 * @returns NextResponse with error format
 *
 * @example
 * return errorResponse('User not found', {
 *   status: 404,
 *   code: ApiErrorCode.NOT_FOUND,
 * });
 *
 * @example
 * return errorResponse('Validation failed', {
 *   status: 400,
 *   code: ApiErrorCode.VALIDATION_ERROR,
 *   details: { email: ['Invalid email format'] },
 * });
 */
export function errorResponse(
  message: string,
  options?: {
    status?: number;
    code?: ApiErrorCode | string;
    details?: Record<string, string[]>;
    requestId?: string;
    headers?: HeadersInit;
  },
): NextResponse<ApiErrorResponse> {
  const response: ApiErrorResponse = {
    success: false,
    error: {
      message,
      code: options?.code,
      details: options?.details,
    },
    meta: createMeta({ requestId: options?.requestId }),
  };

  return NextResponse.json(response, {
    status: options?.status || 500,
    headers: options?.headers,
  });
}

/**
 * Create a 400 Bad Request response
 */
export function badRequestResponse(
  message: string = "Bad request",
  details?: Record<string, string[]>,
  headers?: HeadersInit,
): NextResponse<ApiErrorResponse> {
  return errorResponse(message, {
    status: 400,
    code: ApiErrorCode.INVALID_INPUT,
    details,
    headers,
  });
}

/**
 * Create a 401 Unauthorized response
 */
export function unauthorizedResponse(
  message: string = "Unauthorized",
  headers?: HeadersInit,
): NextResponse<ApiErrorResponse> {
  return errorResponse(message, {
    status: 401,
    code: ApiErrorCode.UNAUTHORIZED,
    headers,
  });
}

/**
 * Create a 403 Forbidden response
 */
export function forbiddenResponse(
  message: string = "Forbidden",
  headers?: HeadersInit,
): NextResponse<ApiErrorResponse> {
  return errorResponse(message, {
    status: 403,
    code: ApiErrorCode.FORBIDDEN,
    headers,
  });
}

/**
 * Create a 404 Not Found response
 */
export function notFoundResponse(
  message: string = "Resource not found",
  headers?: HeadersInit,
): NextResponse<ApiErrorResponse> {
  return errorResponse(message, {
    status: 404,
    code: ApiErrorCode.NOT_FOUND,
    headers,
  });
}

/**
 * Create a 409 Conflict response
 */
export function conflictResponse(
  message: string = "Resource conflict",
  headers?: HeadersInit,
): NextResponse<ApiErrorResponse> {
  return errorResponse(message, {
    status: 409,
    code: ApiErrorCode.CONFLICT,
    headers,
  });
}

/**
 * Create a 500 Internal Server Error response
 */
export function internalErrorResponse(
  message: string = "Internal server error",
  headers?: HeadersInit,
): NextResponse<ApiErrorResponse> {
  return errorResponse(message, {
    status: 500,
    code: ApiErrorCode.INTERNAL_ERROR,
    headers,
  });
}

/**
 * Calculate pagination metadata from array and page parameters
 *
 * @param totalItems - Total number of items
 * @param page - Current page number (1-indexed)
 * @param pageSize - Number of items per page
 * @returns Pagination metadata
 *
 * @example
 * const pagination = calculatePagination(100, 1, 20);
 * // { page: 1, pageSize: 20, totalItems: 100, totalPages: 5, hasNextPage: true, hasPreviousPage: false }
 */
export function calculatePagination(
  totalItems: number,
  page: number,
  pageSize: number,
): PaginationMeta {
  const totalPages = Math.ceil(totalItems / pageSize);

  return {
    page,
    pageSize,
    totalItems,
    totalPages,
    hasNextPage: page < totalPages,
    hasPreviousPage: page > 1,
  };
}

/**
 * Paginate an array of items
 *
 * @param items - Array to paginate
 * @param page - Current page (1-indexed)
 * @param pageSize - Items per page
 * @returns Paginated slice of items and metadata
 *
 * @example
 * const users = await db.getAllUsers();
 * const { items, pagination } = paginateArray(users, 1, 20);
 * return paginatedResponse(items, pagination);
 */
export function paginateArray<T>(
  items: T[],
  page: number,
  pageSize: number,
): {
  items: T[];
  pagination: PaginationMeta;
} {
  const startIndex = (page - 1) * pageSize;
  const endIndex = startIndex + pageSize;
  const paginatedItems = items.slice(startIndex, endIndex);

  return {
    items: paginatedItems,
    pagination: calculatePagination(items.length, page, pageSize),
  };
}

/**
 * Add CORS headers to response
 *
 * @param headers - Existing headers or undefined
 * @returns Headers with CORS added
 */
export function addCorsHeaders(headers?: HeadersInit): HeadersInit {
  const corsHeaders = {
    "Access-Control-Allow-Origin": "*",
    "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
    "Access-Control-Allow-Headers": "Content-Type, Authorization",
  };

  if (!headers) {
    return corsHeaders;
  }

  if (headers instanceof Headers) {
    const newHeaders = new Headers(headers);
    Object.entries(corsHeaders).forEach(([key, value]) => {
      newHeaders.set(key, value);
    });
    return newHeaders;
  }

  if (Array.isArray(headers)) {
    return [...headers, ...Object.entries(corsHeaders)];
  }

  return { ...headers, ...corsHeaders };
}

/**
 * Create a 204 No Content response
 */
export function noContentResponse(
  headers?: HeadersInit,
): NextResponse<undefined> {
  return new NextResponse(undefined, {
    status: 204,
    headers,
  });
}

/**
 * Create a standardized created response (201)
 */
export function createdResponse<T>(
  data: T,
  options?: {
    requestId?: string;
    headers?: HeadersInit;
  },
): NextResponse<ApiSuccessResponse<T>> {
  return successResponse(data, {
    status: 201,
    requestId: options?.requestId,
    headers: options?.headers,
  });
}
