export class ApiError extends Error {
  constructor(
    message: string,
    public readonly status?: number,
    public readonly code?: string,
    public readonly meta?: Record<string, unknown>,
  ) {
    super(message);
    this.name = 'ApiError';
  }
}

export function isApiError(value: unknown): value is ApiError {
  return value instanceof ApiError;
}

export function getApiErrorMessage(error: unknown, fallback: string): string {
  if (isApiError(error)) {
    if (error.message) {
      return error.message;
    }

    if (error.status && error.status >= 500) {
      return 'Der Server hat nicht reagiert. Bitte versuche es später erneut.';
    }

    return fallback;
  }

  if (error instanceof Error && error.message) {
    return error.message;
  }

  return fallback;
}

export function getApiValidationMessage(error: unknown, fallback: string): string {
  if (isApiError(error)) {
    const errors = normalizeValidationErrors(error.meta);
    if (errors.length) {
      return errors.join('\n');
    }
  }

  return getApiErrorMessage(error, fallback);
}

export type ApiErrorEventDetail = {
  message: string;
  status?: number;
  code?: string;
  meta?: Record<string, unknown>;
};

export const API_ERROR_EVENT = 'admin:api:error';

export function emitApiErrorEvent(detail: ApiErrorEventDetail): void {
  if (typeof window === 'undefined') {
    return;
  }

  window.dispatchEvent(new CustomEvent<ApiErrorEventDetail>(API_ERROR_EVENT, { detail }));
}

export function registerApiErrorListener(handler: (detail: ApiErrorEventDetail) => void): () => void {
  if (typeof window === 'undefined') {
    return () => {};
  }

  const listener = (event: Event) => {
    const customEvent = event as CustomEvent<ApiErrorEventDetail>;
    handler(customEvent.detail);
  };

  window.addEventListener(API_ERROR_EVENT, listener as EventListener);
  return () => window.removeEventListener(API_ERROR_EVENT, listener as EventListener);
}

function normalizeValidationErrors(meta?: Record<string, unknown>): string[] {
  if (!meta || typeof meta !== 'object') {
    return [];
  }

  const errors = meta.errors;
  if (!errors || typeof errors !== 'object') {
    return [];
  }

  return Object.values(errors as Record<string, unknown>)
    .flatMap((value) => (Array.isArray(value) ? value : [value]))
    .filter((value): value is string => typeof value === 'string' && value.trim() !== '');
}
