export interface BlazeError {
  domain?: string;
  reason?: string;
  message?: string;
  metadata?: Record<string, string>;
  underlyingError?: string;
}

export class BlazeException extends Error {
  readonly blazeError: BlazeError;

  constructor(blazeError: BlazeError) {
    super(blazeError.message || 'Blaze SDK Error');
    this.name = 'BlazeException';
    this.blazeError = blazeError;
  }

  toString(): string {
    return `BlazeException - For access to more details please cast it into \`BlazeException\`: ${JSON.stringify(this.blazeError)})`;
  }
}

// Helper function to parse BlazeError from a JSON string
export function tryParseBlazeErrorFromPromiseRejection(error: any): BlazeError | null {
  try {
    // Check if this is a Blaze convertible error
    if (error && typeof error === 'object' && error.code === 'BLAZE_CONVERTIBLE_ERROR') {
      let detailsString: string | null = null;

      // React Native NSError structure: details are in userInfo.details
      if (error.userInfo && typeof error.userInfo === 'object' && typeof error.userInfo.details === 'string') {
        detailsString = error.userInfo.details;
      }
      // Fallback: check if details is directly on the error object
      else if (typeof error.details === 'string') {
        detailsString = error.details;
      }

      if (detailsString) {
        return parseBlazeError(detailsString) || null;
      }
    }
  } catch (e) {
    return null;
  }
  return null;
}

// Helper function to parse BlazeError from a JSON string (for event data)
export function parseBlazeError(errorString: string | undefined): BlazeError | undefined {
  if (!errorString || typeof errorString !== 'string') {
    return undefined;
  }

  try {
    const jsonMap = JSON.parse(errorString);
    return jsonMap as BlazeError;
  } catch (e) {
    console.error('Failed to parse BlazeError from string:', errorString, e);
    return undefined;
  }
}

// Helper function to map error to BlazeException or rethrow
export function mapToBlazeErrorOrRethrow(error: any): never {
  const blazeError = tryParseBlazeErrorFromPromiseRejection(error);
  if (blazeError) {
    const exception = new BlazeException(
      blazeError
    );
    throw exception;
  }
  throw error;
}
