import { CSSProperties } from 'glamor';
import { makeAutoObservable } from 'mobx';
import ColorUtils from './color.utils';
import { CssPropertyStyle } from '../style.interface';

export interface ConverterType {
  id: string;
}
/**
 * A converter is a class that can convert a value from one type to another
 */
export default class Converter {
  id: string;
  constructor(props: ConverterType) {
    this.id = props.id;
    makeAutoObservable(this);
  }

  /**
   * Converts CssPropertyStyle to raw Css in Js here it will be equivalent to
   * one line (one property) in a css style sheet
   * It takes into account StyleToken references
   * for instance, if values contain string references such as  'theme.colors.primary'
   * it will not be converted into the actual color value, if user makes
   * keepReferenceValue = true, it will still be 'theme.colors.primary'
   * @param value CssPropertyStyle
   * @returns CSSProperties
   */
  static cssPropertyStyleToCssProperty = (
    value: CssPropertyStyle,
    keepReferenceValue?: boolean
  ): CSSProperties => {
    let v = value?.value;
    if (keepReferenceValue) {
      if (value.reference) {
        const referenceValue = value.reference.value;
        if (referenceValue) {
          if (
            typeof referenceValue === 'string' ||
            typeof referenceValue === 'number'
          ) {
            v = referenceValue;
          } else {
            // referenceValue is an object  (color definition)
            v =
              ColorUtils.toRgbaStringFromRgbaObject(referenceValue.rgb) ||
              value?.value;
          }
        }
      }
    }
    return {
      [value.property]: v
    };
  };
  /**
   * Converts CssPropertyStyle[] to raw Css in Js here it will be equivalent to
   * multiple lines (multiple properties) in a css style sheet
   * It takes into account StyleToken references
   * for instance, if values contain string references such as  'theme.colors.primary'
   * it will not be converted into the actual color value, if user makes
   * keepReferenceValue = true, it will still be 'theme.colors.primary'
   * @param value CssPropertyStyle[]
   * @param keepReferenceValue @optional if true, it will keep the reference value
   * @returns CSSProperties
   */
  static toCssObjectFromCssPropertyStyleList = (
    value: CssPropertyStyle[],
    keepReferenceValue?: boolean
  ): CSSProperties => {
    let styles: CSSProperties = {};
    value.forEach((v) => {
      styles = {
        ...styles,
        ...Converter.cssPropertyStyleToCssProperty(v, keepReferenceValue)
      };
    });
    return styles;
  };

  /**
   * Converts raw Css in Js to CssPropertyStyle[]
   * @param value a raw css in js object to CssPropertyStyle
   * @returns CssPropertyStyle
   */
  static cssPropertyToCssPropertyStyle = (
    value: CSSProperties
  ): CssPropertyStyle[] => {
    return Object.keys(value).map((key) => {
      return {
        property: key,
        value: value[key],
        reference: null,
        isSelector: false
      };
    });
  };
}
