/**
 * Copyright (c) Tiny Technologies, Inc. All rights reserved.
 * Licensed under the LGPL or a commercial license.
 * For LGPL see License.txt in the project root for license information.
 * For commercial licenses see https://www.tiny.cloud/
 */

import { Toggling } from '@ephox/alloy';
import { Objects } from '@ephox/boulder';
import { Arr, Fun, Id, Merger } from '@ephox/katamari';

import DefaultStyleFormats from '../features/DefaultStyleFormats';
import StylesMenu from '../ui/StylesMenu';
import StyleConversions from './StyleConversions';

const register = function (editor, settings) {

  const isSelectedFor = function (format) {
    return function () {
      return editor.formatter.match(format);
    };
  };

  const getPreview = function (format) {
    return function () {
      const styles = editor.formatter.getCssText(format);
      return styles;
    };
  };

  const enrichSupported = function (item) {
    return Merger.deepMerge(item, {
      isSelected: isSelectedFor(item.format),
      getPreview: getPreview(item.format)
    });
  };

  // Item that triggers a submenu
  const enrichMenu = function (item) {
    return Merger.deepMerge(item, {
      isSelected: Fun.constant(false),
      getPreview: Fun.constant('')
    });
  };

  const enrichCustom = function (item) {
    const formatName = Id.generate(item.title);
    const newItem = Merger.deepMerge(item, {
      format: formatName,
      isSelected: isSelectedFor(formatName),
      getPreview: getPreview(formatName)
    });
    editor.formatter.register(formatName, newItem);
    return newItem;
  };

  const formats = Objects.readOptFrom(settings, 'style_formats').getOr(DefaultStyleFormats);

  const doEnrich = function (items) {
    return Arr.map(items, function (item) {
      if (Objects.hasKey(item, 'items')) {
        const newItems = doEnrich(item.items);
        return Merger.deepMerge(
          enrichMenu(item),
          {
            items: newItems
          }
        );
      } else if (Objects.hasKey(item, 'format')) {
        return enrichSupported(item);
      } else {
        return enrichCustom(item);
      }
    });
  };

  return doEnrich(formats);
};

const prune = function (editor, formats) {

  const doPrune = function (items) {
    return Arr.bind(items, function (item) {
      if (item.items !== undefined) {
        const newItems = doPrune(item.items);
        return newItems.length > 0 ? [ item ] : [ ];
      } else {
        const keep = Objects.hasKey(item, 'format') ? editor.formatter.canApply(item.format) : true;
        return keep ? [ item ] : [ ];
      }
    });
  };

  const prunedItems = doPrune(formats);
  return StyleConversions.expand(prunedItems);
};

const ui = function (editor, formats, onDone) {
  const pruned = prune(editor, formats);

  return StylesMenu.sketch({
    formats: pruned,
    handle (item, value) {
      editor.undoManager.transact(function () {
        if (Toggling.isOn(item)) {
          editor.formatter.remove(value);
        } else {
          editor.formatter.apply(value);
        }
      });
      onDone();
    }
  });
};

export default {
  register,
  ui
};