import React from 'react';
import { ErrorType, StationError } from '../components/models';
import { mapError } from './ErrorMapper/ErrorMapper';

/**
 * Converts an `ErrorType` object into a station error.
 * @param error The error that should be converted. This is optional, so an error can be created, even if there is no original ErrorType object.
 * @param defaultTitle The message that should be used as default title, in case the `ErrorType` object is no `StationError` that already defines a title.
 * @param defaultBody The body that should be used in case the function can not infer the body of the message.
 * @returns A station error object
 */
export const ErrorTypeToStationError = (
  originalError?: ErrorType,
  defaultTitle = 'An error occurred.',
  defaultBody?: string,
): StationError => {
  const error = mapError(
    originalError ?? { title: defaultTitle, body: defaultBody },
  );
  let stationError: StationError;
  if (isStationError(error)) {
    // we already got a station error
    stationError = error;
  } else {
    // we got either a string or an object or no error at all
    let originalError: string | undefined;
    let message: string | undefined;

    if (typeof error === 'string') {
      message = error;
    } else if (
      typeof error === 'object' &&
      String(error) !== '[object Object]'
    ) {
      message = String(error);
      originalError = JSON.stringify(error, undefined, 2);
    } else if (typeof error === 'object') {
      originalError = JSON.stringify(error, undefined, 2);
    } else if (defaultBody) {
      originalError = defaultBody;
    }

    stationError = {
      title: defaultTitle,
      body: (originalError !== undefined || message !== undefined) && (
        <>
          {message && <p>{message}</p>}
          {originalError && (
            <>
              <i>Original Error:</i>
              <pre>{originalError}</pre>
            </>
          )}
        </>
      ),
    };
  }

  return stationError;
};

const isStationError = (value: unknown): value is StationError => {
  function isStationErrorLike(
    given: unknown,
  ): given is Partial<Record<keyof StationError, unknown>> {
    return typeof given === 'object' && given !== null && 'title' in given;
  }

  return isStationErrorLike(value) && typeof value.title === 'string';
};
