import { createElementVNode as _createElementVNode, createVNode as _createVNode, normalizeClass as _normalizeClass, normalizeStyle as _normalizeStyle, mergeProps as _mergeProps, withDirectives as _withDirectives } from "vue";
// Styles
import "./VPie.css";

// Components
import { makeVPieSegmentProps, VPieSegment } from "./VPieSegment.js";
import { VPieTooltip } from "./VPieTooltip.js";
import { VAvatar } from "../../components/VAvatar/index.js";
import { VChip } from "../../components/VChip/index.js";
import { VChipGroup } from "../../components/VChipGroup/index.js";
import { VDefaultsProvider } from "../../components/VDefaultsProvider/index.js"; // Composables
import { useColor } from "../../composables/color.js";
import { makeDensityProps } from "../../composables/density.js"; // Directives
import vClickOutside from "../../directives/click-outside/index.js"; // Utilities
import { computed, shallowRef, toRef, watch } from 'vue';
import { formatTextTemplate } from "./utils.js";
import { convertToUnit, genericComponent, pick, propsFactory } from "../../util/index.js"; // Types
export const makeVPieProps = propsFactory({
  title: String,
  bgColor: String,
  items: {
    type: Array,
    default: () => []
  },
  palette: {
    type: Array,
    default: () => []
  },
  itemKey: {
    type: String,
    default: 'key'
  },
  itemValue: {
    type: String,
    default: 'value'
  },
  itemTitle: {
    type: String,
    default: 'title'
  },
  size: {
    type: [Number, String],
    default: 250
  },
  rotate: [Number, String],
  gaugeCut: [Number, String],
  legend: {
    type: [Boolean, Object],
    default: false
  },
  tooltip: {
    type: [Boolean, Object],
    default: false
  },
  ...makeDensityProps(),
  ...pick(makeVPieSegmentProps(), ['animation', 'gap', 'rounded', 'innerCut', 'hoverScale', 'hideSlice', 'reveal'])
}, 'VPie');
export const VPie = genericComponent()({
  name: 'VPie',
  directives: {
    vClickOutside
  },
  props: makeVPieProps(),
  setup(props, {
    slots
  }) {
    const legendConfig = computed(() => ({
      visible: !!props.legend,
      position: 'bottom',
      textFormat: '[title]',
      ...(typeof props.legend === 'object' ? props.legend : {})
    }));
    const {
      colorClasses,
      colorStyles
    } = useColor(() => ({
      background: props.bgColor
    }));
    const textColorStyles = toRef(() => pick(colorStyles.value, ['color', 'caretColor']));
    const legendAvatarSize = toRef(() => ({
      default: 20,
      comfortable: 18,
      compact: 16
    })[props.density ?? 'default']);
    const legendDirection = toRef(() => ['left', 'right'].includes(legendConfig.value.position) ? 'vertical' : 'horizontal');
    const legendMode = toRef(() => !legendConfig.value.visible ? 'hidden' : legendConfig.value.position);
    const legendTextFormatFunction = toRef(() => item => {
      return typeof legendConfig.value.textFormat === 'function' ? legendConfig.value.textFormat(item) : formatTextTemplate(legendConfig.value.textFormat, item);
    });
    const arcs = computed(() => {
      // hidden items get (value: 0) to trigger disappearing animation
      return props.items.filter(Boolean).map((item, index) => {
        return {
          key: item[props.itemKey],
          color: item.color ?? colorFromPalette(index),
          value: item[props.itemValue],
          title: String(item[props.itemTitle]),
          pattern: item.pattern ?? patternFromPalette(index),
          raw: item
        };
      });
    });
    const visibleItemsKeys = shallowRef([]);
    watch(() => arcs.value.length, () => {
      // reset when number of items changes
      visibleItemsKeys.value = arcs.value.map(a => a.key);
    }, {
      immediate: true
    });
    const visibleItems = computed(() => {
      // hidden items get (value: 0) to trigger disappearing animation
      return arcs.value.map(item => {
        return isVisible(item) ? item : {
          ...item,
          value: 0
        };
      });
    });
    const total = computed(() => visibleItems.value.reduce((sum, item) => sum + item.value, 0));
    const gaugeCut = toRef(() => Number(props.gaugeCut ?? 0));
    const gaugeOffset = computed(() => (1 - Math.cos(Math.PI * Math.min(90, gaugeCut.value / 2) / 180)) / 2);
    const rotateDeg = computed(() => `${gaugeCut.value ? 180 + gaugeCut.value / 2 : props.rotate ?? 0}deg`);
    function arcOffset(index) {
      return visibleItems.value.slice(0, index).reduce((acc, s) => acc + (total.value > 0 ? s.value / total.value : 0) * (360 - gaugeCut.value), 0);
    }
    function arcSize(v) {
      return v / total.value * (100 - gaugeCut.value / 3.6);
    }
    function colorFromPalette(index) {
      if (props.palette.length === 0) return undefined;
      const paletteItem = props.palette[index % props.palette.length];
      return typeof paletteItem === 'object' ? paletteItem.color : paletteItem;
    }
    function patternFromPalette(index) {
      if (props.palette.length === 0) return undefined;
      const paletteItem = props.palette[index % props.palette.length];
      return typeof paletteItem === 'object' ? paletteItem.pattern : undefined;
    }
    function isVisible(item) {
      return visibleItemsKeys.value.includes(item.key);
    }
    function toggle(item) {
      if (isVisible(item)) {
        visibleItemsKeys.value = visibleItemsKeys.value.filter(x => x !== item.key);
      } else {
        visibleItemsKeys.value = [...visibleItemsKeys.value, item.key];
      }
    }
    const activeItemKey = shallowRef(null);
    const tooltipItem = shallowRef(null);
    const tooltipVisible = shallowRef(false);
    const tooltipTarget = shallowRef([0, 0]);
    let mouseLeaveTimeout = null;
    function setItemActive(item, active) {
      activeItemKey.value = active ? item.key : null;
      if (props.tooltip) {
        setTooltip(item, active);
      }
    }
    function setTooltip(item, active) {
      clearTimeout(mouseLeaveTimeout);
      if (active) {
        tooltipVisible.value = true;
        tooltipItem.value = item;
      } else {
        mouseLeaveTimeout = setTimeout(() => {
          tooltipVisible.value = false;

          // intentionally reusing timeout here
          mouseLeaveTimeout = setTimeout(() => {
            tooltipItem.value = null;
          }, 500);
        }, 100);
      }
    }
    let frame = -1;
    function onSvgMousemove({
      clientX,
      clientY
    }) {
      cancelAnimationFrame(frame);
      frame = requestAnimationFrame(() => {
        tooltipTarget.value = [clientX, clientY];
      });
    }
    function onSvgTouchstart({
      touches
    }) {
      if (!touches) return;
      const {
        clientX,
        clientY
      } = touches[0];
      tooltipTarget.value = [clientX, clientY];
    }
    function onSvgClickOutside() {
      activeItemKey.value = null;
      tooltipVisible.value = false;
    }
    return () => {
      const segmentProps = pick(props, ['animation', 'gap', 'rounded', 'hideSlice', 'reveal', 'innerCut', 'hoverScale']);
      const defaultTooltipTransition = {
        name: 'fade-transition',
        duration: 150
      };
      const tooltipProps = {
        item: tooltipItem.value,
        modelValue: tooltipVisible.value,
        titleFormat: typeof props.tooltip === 'object' ? props.tooltip.titleFormat : '[title]',
        subtitleFormat: typeof props.tooltip === 'object' ? props.tooltip.subtitleFormat : '[value]',
        transition: typeof props.tooltip === 'object' ? props.tooltip.transition : defaultTooltipTransition,
        offset: typeof props.tooltip === 'object' ? props.tooltip.offset : 16,
        target: tooltipTarget.value
      };
      const legendDefaults = {
        VChipGroup: {
          direction: legendDirection.value
        },
        VChip: {
          density: props.density
        },
        VAvatar: {
          size: legendAvatarSize.value
        }
      };
      const tooltipDefaults = {
        VAvatar: {
          size: typeof props.tooltip === 'object' ? props.tooltip.avatarSize ?? 28 : 28
        }
      };
      const avatarSlot = ({
        item
      }) => _createVNode(VAvatar, {
        "color": item.color,
        "start": true
      }, {
        default: () => [item.pattern && _createElementVNode("svg", {
          "height": "40",
          "width": "40"
        }, [_createElementVNode("rect", {
          "width": "40",
          "height": "40",
          "fill": item.pattern
        }, null)])]
      });
      return _createElementVNode("div", {
        "class": _normalizeClass(['v-pie', `v-pie--legend-${legendMode.value}`]),
        "style": {
          '--v-pie-size': convertToUnit(props.size)
        }
      }, [slots.title?.() ?? (props.title && _createElementVNode("div", {
        "class": "v-pie__title"
      }, [props.title])), _createElementVNode("div", {
        "class": _normalizeClass(['v-pie__content', colorClasses.value]),
        "style": _normalizeStyle([{
          transform: `rotate(${rotateDeg.value})`,
          marginBottom: `calc(-1 * ${convertToUnit(props.size)} * ${gaugeOffset.value})`
        }, textColorStyles.value])
      }, [_createElementVNode("div", {
        "class": _normalizeClass(['v-pie__content-underlay', colorClasses.value]),
        "style": _normalizeStyle(colorStyles.value)
      }, null), _withDirectives(_createElementVNode("svg", {
        "xmlns": "http://www.w3.org/2000/svg",
        "viewBox": "0 0 100 100",
        "class": "v-pie__segments",
        "onMousemove": onSvgMousemove,
        "onTouchstart": onSvgTouchstart
      }, [arcs.value.map((item, index) => _createVNode(VPieSegment, _mergeProps(segmentProps, {
        "key": item.key,
        "active": activeItemKey.value === item.key,
        "color": item.color,
        "value": isVisible(item) ? arcSize(item.value) : 0,
        "rotate": arcOffset(index),
        "pattern": item.pattern,
        "onUpdate:active": val => setItemActive(item, val),
        "onTouchend": () => setItemActive(item, true)
      }), null))]), [[vClickOutside, {
        handler: onSvgClickOutside
      }]]), _createElementVNode("div", {
        "class": "v-pie__center-content",
        "style": {
          transform: `translate(-50%, -50%)
                  rotate(-${rotateDeg.value})
                  translateY(calc(-100% * ${gaugeOffset.value}))`
        }
      }, [_createElementVNode("div", null, [slots.center?.({
        total: total.value
      })])])]), legendConfig.value.visible && _createVNode(VDefaultsProvider, {
        "key": "legend",
        "defaults": legendDefaults
      }, {
        default: () => [_createElementVNode("div", {
          "class": "v-pie__legend"
        }, [slots.legend?.({
          isActive: isVisible,
          toggle,
          items: arcs.value,
          total: total.value
        }) ?? _createVNode(VChipGroup, {
          "column": true,
          "multiple": true,
          "modelValue": visibleItemsKeys.value,
          "onUpdate:modelValue": $event => visibleItemsKeys.value = $event
        }, {
          default: () => [arcs.value.map(item => _createVNode(VChip, {
            "value": item.key
          }, {
            prepend: () => avatarSlot({
              item
            }),
            default: () => _createElementVNode("div", {
              "class": "v-pie__legend__text"
            }, [slots['legend-text']?.({
              item,
              total: total.value
            }) ?? legendTextFormatFunction.value(item)])
          }))]
        })])]
      }), !!props.tooltip && _createVNode(VDefaultsProvider, {
        "defaults": tooltipDefaults
      }, {
        default: () => [_createVNode(VPieTooltip, tooltipProps, {
          default: slots.tooltip ? slotProps => slots.tooltip?.({
            ...slotProps,
            total: total.value
          }) : undefined,
          prepend: avatarSlot
        })]
      })]);
    };
  }
});
//# sourceMappingURL=VPie.js.map