export interface FullDomainError {
  title: string
  message?: string
  detail?: string
  source?: {
    pointer: string
    parameter: string
  }
}

export type ShortDomainError = FullDomainError['title']

export interface BaseDomainError {
  base: ShortDomainError[]
}

export interface ErrorListResponse {
  errors: BaseDomainError | FullDomainError[] | ShortDomainError[]
}

export interface SingleErrorResponse {
  error: ShortDomainError
}

export type ErrorResponse = ErrorListResponse | SingleErrorResponse

export type ErrorPayload<T = unknown> = {
  body: ErrorResponse
  statusCode: number
  responseData?: T | null
}

export type MaybeError = ShortDomainError | FullDomainError | undefined

export const buildUnknownError = (statusCode: number) => `Unknown Error occurred from Server with status code ${statusCode}`

export class ApiError<T = unknown> extends Error {
  readonly body: ErrorResponse
  readonly statusCode: number
  readonly responseData: T | null
  constructor(payload: ErrorPayload<T>) {
    super('Caught an error while fetching the API Server endpoint...')
    this.name = 'ApiError'
    this.body = payload.body
    this.statusCode = payload.statusCode
    this.responseData = payload?.responseData || null
  }
}

export function isErrorResponse<R>(data: R | ErrorResponse): data is ErrorResponse {
  return isSingleErrorResponse<R>(data) || isErrorListResponse<R>(data)
}

export function isSingleErrorResponse<R>(data: R | ErrorResponse): data is SingleErrorResponse {
  return typeof data === 'object' && data !== null && 'error' in data
}

export function isErrorListResponse<R>(data: R | ErrorResponse): data is ErrorListResponse {
  return typeof data === 'object' && data !== null && 'errors' in data
}

export function isShortDomainError(error: MaybeError): error is ShortDomainError {
  return typeof error === 'string'
}

/**
 * Express-validator error format
 */
interface ValidationError {
  type: string
  value: string
  msg: string
  path: string
  location: string
}

/**
 * Service error format (e.g., ZeroBounce)
 */
interface ServiceErrorResponse {
  status: 'error'
  message: string
}

function isValidationErrorArray(data: unknown): data is ValidationError[] {
  return Array.isArray(data) && data.length > 0 && 'msg' in data[0] && 'path' in data[0]
}

function isServiceErrorResponse(data: unknown): data is ServiceErrorResponse {
  return typeof data === 'object' && data !== null && 'status' in data && 'message' in data
}

/**
 * Extract error message from ApiError
 * Handles multiple formats:
 * 1. { errors: [{ msg, path }] } - express-validator
 * 2. { status: "error", message: "..." } - service errors (ZeroBounce)
 * 3. { error: "..." } - single error
 * 4. { errors: { base: [...] } } - base errors
 */
export function extractErrorMessage(apiError: ApiError): string {
  const responseData = apiError.responseData
  
  // Check for service error format: { status: "error", message: "..." }
  if (isServiceErrorResponse(responseData)) {
    return responseData.message
  }
  
  // Check for express-validator format: { errors: [{ msg, path }] }
  if (responseData && typeof responseData === 'object' && 'errors' in responseData) {
    const errors = (responseData as { errors: unknown }).errors
    if (isValidationErrorArray(errors)) {
      const emailError = errors.find(e => e.path === 'email')
      if (emailError) {
        return emailError.msg
      }
      return errors[0].msg
    }
  }
  
  // Fallback to original logic for other formats
  const body = isSingleErrorResponse(apiError.body) ? [apiError.body.error] : apiError.body.errors
  const errors = Array.isArray(body) ? body : body.base
  const firstError = errors.at(0)
  if (firstError === undefined) {
    return buildUnknownError(apiError.statusCode)
  }
  if (isShortDomainError(firstError)) {
    return firstError
  }
  if ('message' in firstError && firstError.message) {
    return firstError.message
  }
  return firstError.title
}

/**
 * Extract email suggestion from error message
 * Parses "Did you mean user@gmail.com?" format
 */
export function extractEmailSuggestion(apiError: ApiError): string | null {
  const responseData = apiError.responseData
  
  if (responseData && typeof responseData === 'object' && 'errors' in responseData) {
    const errors = (responseData as { errors: unknown }).errors
    if (isValidationErrorArray(errors)) {
      const emailError = errors.find(e => e.path === 'email')
      if (emailError) {
        const match = emailError.msg.match(/Did you mean (.+)\?/)
        return match ? match[1] : null
      }
    }
  }
  
  return null
}
