import type {
  CollectedData,
  ExternalCollectedData,
  ExtraData,
  OnCanceledCallback,
  OnCompleteCallback,
  OnErrorCallback,
  OnEventCallback,
  OnReadyCallback,
} from './callbacks';
import { Fields, InquiryField, RawInquiryField } from './fields';
import { InquiryEvent } from './InquiryEvent';
import {
  DocumentStepData,
  GovernmentIdStepData,
  SelfieStepData,
  UiStepData,
} from './StepData';

const HEX_REGEX = /^[a-fA-F0-9]{6}$/;
export function processThemeValues(themeObject: Object) {
  const result: { [key: string]: string } = {};
  for (const [key, value] of Object.entries(themeObject)) {
    if (value === null) {
      continue;
    }

    if (key.includes('Color')) {
      let colorValue = value;
      if (value[0] === '#') {
        colorValue = value.slice(1);
      }

      if (HEX_REGEX.test(colorValue)) {
        result[key] = `#${colorValue}`;
      } else {
        continue;
      }
    } else {
      result[key] = value.toString();
    }
  }

  return result;
}

export function callOnCompleteCallback(
  event: {
    inquiryId: string;
    status: string;
    fields: Record<string, RawInquiryField>;
    collectedData: ExternalCollectedData | null;
  },
  callback: OnCompleteCallback | undefined
) {
  if (callback) {
    let fields: Fields = {};
    for (let key of Object.keys(event.fields || {})) {
      let field = event.fields[key];
      if (field == undefined) {
        fields[key] = new InquiryField.Unknown('null');
        continue;
      }
      switch (field.type) {
        case 'integer':
          fields[key] = new InquiryField.Integer(Number.parseInt(field.value));
          break;
        case 'boolean':
          fields[key] = new InquiryField.Boolean(field.value);
          break;
        case 'string':
          fields[key] = new InquiryField.String(field.value);
          break;
        default:
          fields[key] = new InquiryField.Unknown(field.type);
          break;
      }
    }

    let collectedData: CollectedData | null = null;

    let stepData = event.collectedData?.stepData;
    if (stepData != null) {
      // Translate the step data from JSON to actual class objects
      let translatedStepData = [];

      for (let stepDatum of stepData) {
        switch (stepDatum.type) {
          case 'DocumentStepData':
            translatedStepData.push(
              Object.assign(new DocumentStepData(), stepDatum)
            );
            break;
          case 'GovernmentIdStepData':
            translatedStepData.push(
              Object.assign(new GovernmentIdStepData(), stepDatum)
            );
            break;
          case 'SelfieStepData':
            translatedStepData.push(
              Object.assign(new SelfieStepData(), stepDatum)
            );
            break;
          case 'UiStepData':
            translatedStepData.push(Object.assign(new UiStepData(), stepDatum));
            break;
        }
      }

      collectedData = {
        stepData: translatedStepData,
      };
    }

    let extraData: ExtraData = {
      collectedData: collectedData,
    };

    callback(event.inquiryId, event.status, fields, extraData);
  }
}

export function callOnCanceledCallback(
  event: { inquiryId?: string; sessionToken?: string },
  callback: OnCanceledCallback | undefined
) {
  if (callback) callback(event.inquiryId, event.sessionToken);
}

export function callOnErrorCallback(
  event: { debugMessage: string; errorCode?: string },
  callback: OnErrorCallback | undefined
) {
  if (callback) callback(new Error(event.debugMessage), event.errorCode);
}

export function callOnReadyCallback(callback: OnReadyCallback | undefined) {
  if (callback) callback();
}

export function callOnEventCallback(
  event: { event: any },
  callback: OnEventCallback | undefined
) {
  if (callback) {
    const parsedEvent = InquiryEvent.fromJson(event.event);
    if (parsedEvent) {
      callback(parsedEvent);
    }
  }
}
