import {
  apiErrorResponseSchema,
  type ApiErrorResponse,
  type ApiSuccessResponse,
} from "@customer-portal/domain/common";
import type { ZodTypeAny, infer as ZodInfer } from "zod";

/**
 * API Response Helper Types and Functions
 *
 * Generic utilities for working with API responses
 */

/**
 * Generic API response wrapper
 */
export type ApiResponse<T> = {
  data?: T;
  error?: unknown;
};

/**
 * Extract data from API response or return null
 * Useful for optional data handling
 */
export function getNullableData<T>(response: ApiResponse<T>): T | null {
  if (response.error || response.data === undefined) {
    return null;
  }
  return response.data;
}

/**
 * Extract data from API response or throw error
 */
export function getDataOrThrow<T>(response: ApiResponse<T>, errorMessage?: string): T {
  if (response.error || response.data === undefined) {
    throw new Error(errorMessage || "Failed to fetch data");
  }
  return response.data;
}

/**
 * Extract data from API response or return default value
 */
export function getDataOrDefault<T>(response: ApiResponse<T>, defaultValue: T): T {
  return response.data ?? defaultValue;
}

/**
 * Check if response has an error
 */
export function hasError<T>(response: ApiResponse<T>): boolean {
  return !!response.error;
}

/**
 * Check if response has data
 */
export function hasData<T>(response: ApiResponse<T>): boolean {
  return response.data !== undefined && !response.error;
}

export type DomainApiResponse<T> = ApiSuccessResponse<T> | ApiErrorResponse;

export function assertSuccess<T>(response: DomainApiResponse<T>): ApiSuccessResponse<T> {
  if (response.success === true) {
    return response;
  }
  throw new Error(response.error.message);
}

export function parseDomainResponse<T>(
  response: DomainApiResponse<T>,
  parser?: (payload: T) => T
): T {
  const success = assertSuccess(response);
  return parser ? parser(success.data) : success.data;
}

export function parseDomainError(payload: unknown): ApiErrorResponse | null {
  const parsed = apiErrorResponseSchema.safeParse(payload);
  return parsed.success ? parsed.data : null;
}

export function buildSuccessResponse<T extends ZodTypeAny>(
  data: ZodInfer<T>,
  schema: T
): ApiSuccessResponse<ZodInfer<T>> {
  return {
    success: true,
    data: schema.parse(data),
  };
}
