import { CSSProperties } from 'glamor';
import { camelCase } from './string/camelCase';
import { colorsLookupTable } from '../themes/colors.lookup';
import { Theme } from '../themes/Theme';
import {
  getStyleTokenReferenceType,
  getValueReferenceStringFromObject,
  hasColorReference
} from '../themes/utils/tokens.utils';
import { isSelector } from './CSS';
import {
  CssPropertyStyle,
  StyleTokenReference
} from '../themes/style.interface';

/**
 * Get styles for focus events
 * @param keyboard styles for keyboard focus
 * @param mouse styles for mouse focus
 * @returns
 */
export function createFocusPseudoclassicSelector(
  keyboard: CSSProperties
): CSSProperties {
  return {
    ':focus': {
      outline: 'none',
      ...keyboard,
      ':focus-visible': {
        outline: 'none',
        ...keyboard
      },
      ':not(:focus-visible)': {
        outline: 'none'
        // ...mouse
      }
    }
  };
}

export const parseCssPropertyStyle = (value: CssPropertyStyle[]): string => {
  const v = value?.map((style) => {
    if (style.isSelector) {
      if (Array.isArray(style.value)) {
        return `"${style.property}": {${parseCssPropertyStyle(style.value)}}`;
      }
      return '';
    } else {
      const property = camelCase(style?.property);
      return `"${property || ''}": "${style?.value || ''}"`;
    }
  });

  return `${v.join(', ')}`;
};

export const toCss = (value: CssPropertyStyle[]): object => {
  if (!value) {
    return {};
  }
  try {
    return JSON.parse(`{${parseCssPropertyStyle(value)}}`);
  } catch (error) {
    console.log({ error, value });
    return {};
  }
};

export class StyleUtils {
  /**
   * Convert Css Properties into CssPropertyStyle[]
   * @param value style in the format of CssProperties (css in JS)
   * @param lookup a lookup table to convert css properties to css property styles, if available
   * @param namespace to better create the style, we can namespace the style this is the value that
   * that will be used to create the base component
   * @returns CssPropertyStyle[]
   */
  static toCssPropertyStyle = (
    value: CSSProperties,
    lookup: { [id: string]: string },
    namespace?: string
  ): CssPropertyStyle[] => {
    const convert = (v: CSSProperties): CssPropertyStyle[] => {
      return Object.keys(v).map((k) => {
        const currentValue = v[k];
        const isColorKey = hasColorReference(k);
        if (isColorKey) {
          const itemInLookup: any = namespace
            ? colorsLookupTable[namespace]
            : undefined;
          let colorReference: string | undefined;
          if (itemInLookup) {
            colorReference = itemInLookup[k];
          }
          const color = colorReference
            ? `theme.${colorReference}`
            : currentValue;
          const cssPropertyValue: CssPropertyStyle = {
            property: k,
            value: color,
            isSelector: isSelector(k),
            reference: colorReference
              ? {
                  type: 'color',
                  value: color,
                  key: color
                }
              : null
          };
          return cssPropertyValue;
        }
        if (
          typeof currentValue !== 'string' &&
          typeof currentValue !== 'number'
        ) {
          const cssPropertyValue: CssPropertyStyle = {
            property: k,
            value: convert(currentValue),
            isSelector: isSelector(k),
            reference: null
          };
          return cssPropertyValue;
        } else {
          const referenceValue = getValueReferenceStringFromObject(
            currentValue,
            lookup,
            namespace
          );

          const reference: StyleTokenReference | null =
            referenceValue && lookup[referenceValue]
              ? {
                  type: getStyleTokenReferenceType(referenceValue),
                  value: currentValue,
                  key: referenceValue
                }
              : null;
          const cssPropertyValue: CssPropertyStyle = {
            property: k,
            value: referenceValue || currentValue,
            isSelector: isSelector(k),
            reference: reference
          };
          return cssPropertyValue;
        }
      });
    };

    const css = convert(value);

    return css;
  };

  // static toSnippetFromStyle = (style: Style): CssSnippet => {
  //   const snippet = new CssSnippet({
  //     id: style.id,
  //     value: style.code,
  //     map: {}, // TODO: add map
  //     baseComponent: style.baseComponent,
  //     description: style.variant,
  //     previewWithTag: style.previewWithTag,
  //     permission: "private", // assuming private here but, TODO
  //   });
  //   return snippet;
  // };

  /**
   * Convert a themed or tokenized style to a css style with raw values
   * @param style with color or design tokens
   * @returns css style with raw values
   */
  static toRawStyle = (style: CSSProperties, theme: Theme): CSSProperties => {
    const rawStyle: CSSProperties = {};

    Object.keys(style).forEach((property) => {
      const value = style[property];
      let rawValue = value;
      if (typeof value === 'string') {
        if (value.startsWith('theme.')) {
          // value is a color token
          // get the value from the theme
          Object.keys(theme.palette).forEach((paletteId) => {
            const palette = theme.palette[paletteId];
            if (palette.id === paletteId) {
              // palette is the one we are looking for
              const colorKey = value.replace('theme.', '');
              const color = palette.colors[colorKey];
              rawValue = color;
            }
          });
        }
      }
      rawStyle[property] = rawValue;
    });

    return rawStyle;
  };
}
