<template>
  <div v-click-outside:[true]="handleClose" :class="classes">
    <div ref="reference" :class="wrapClasses" @click="toggleVisible">
      <slot>
        <i-input class="ivu-color-picker-input" v-model="currentValue" @on-change="colorChange(currentValue)">
          <template #append>
            <div :class="[prefixCls + '-color']">
              <div v-show="modelValue === '' && !visible" :class="[prefixCls + '-color-empty']">
                <i :class="[iconPrefixCls, iconPrefixCls + '-ios-close']"></i>
              </div>
              <div v-show="modelValue || visible" :style="displayedColorStyle"></div>
            </div>
          </template>
        </i-input>
      </slot>
    </div>
    <Drop ref="drop" :visible="visible" :placement="placement" :transfer="transfer" :classes="dropClasses" transition-name="transition-drop">
      <transition name="fade">
        <div class="ivu-color-picker-down" v-if="visible">
          <ColorPanel v-model="currentValue" :format="format" @on-change="colorChange" @on-input="colorChange($event, 'input')"/>
        </div>
      </transition>
    </Drop>
  </div>
</template>
<script>
import { getCurrentInstance } from "vue";
import Drop from "./dropdown.vue";
import ColorPanel from './ColorPanel.vue'
import util from '../../libs/util';
import Prefixes from "./prefixMixin";
import tinycolor from "tinycolor2";

export default {
  name: "ColorPicker",
  components: { Drop, ColorPanel },
  mixins: [Prefixes],
  emits: [
    "on-open-change",
    "on-input",
    "on-change",
    "update:modelValue",
  ],
  props: {
    modelValue: {
      type: String,
      default: undefined,
    },
    alpha: {
      type: Boolean,
      default: true,
    },
    format: {
      type: String,
      validator(value) {
        return util.oneOf(value, ["hsl", "hsv", "hex", "rgb"]);
      },
      default: undefined,
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    size: {
      validator(value) {
        return util.oneOf(value, ["small", "large", "default"]);
      },
      default() {
        const global = getCurrentInstance().appContext.config.globalProperties;
        return !global.$VIEWUI || global.$VIEWUI.size === ""
          ? "default"
          : global.$VIEWUI.size;
      },
    },
    placement: {
      type: String,
      validator(value) {
        return util.oneOf(value, [
          "top",
          "top-start",
          "top-end",
          "bottom",
          "bottom-start",
          "bottom-end",
          "left",
          "left-start",
          "left-end",
          "right",
          "right-start",
          "right-end",
        ]);
      },
      default: "bottom",
    },
    transfer: {
      type: Boolean,
      default() {
        const global = getCurrentInstance().appContext.config.globalProperties;
        return !global.$VIEWUI || global.$VIEWUI.transfer === ""
          ? false
          : global.$VIEWUI.transfer;
      },
    }
  },
  data() {
    return {
      currentValue: this.modelValue || "",
      visible: false
    };
  },
  computed: {
    transition() {
      return util.oneOf(this.placement, ["bottom-start", "bottom", "bottom-end"])
        ? "slide-up"
        : "fade";
    },
    classes() {
      return [
        `${this.prefixCls}`,
        {
          [`${this.prefixCls}-transfer`]: this.transfer,
        },
      ];
    },
    wrapClasses() {
      return [
        `${this.prefixCls}-rel`,
        `${this.prefixCls}-${this.size}`,
        `${this.inputPrefixCls}-wrapper`,
        `${this.inputPrefixCls}-wrapper-${this.size}`,
        {
          [`${this.prefixCls}-disabled`]: this.disabled,
        },
      ];
    },
    dropClasses() {
      return {
        [`${this.transferPrefixCls}-no-max-height`]: true,
        [`${this.prefixCls}-transfer`]: this.transfer
      };
    },
    displayedColorStyle() {
      return {
        backgroundColor: this.currentValue,
      };
    }
  },
  watch: {
    modelValue(newVal) {
      this.currentValue = newVal;
    },
    visible(val) {
      this.$refs.drop[val ? "update" : "destroy"]();
      this.$emit("on-open-change", Boolean(val));
    }
  },
  methods: {
    colorChange(value, mode = 'change') {
      if (!tinycolor(value).isValid()) {
        return
      }
      this.$emit("update:modelValue", this.currentValue);
      this.$emit(`on-${mode}`, this.currentValue);
    },
    handleClose(event) {
      if (this.visible) {
        if (this.transfer) {
          const $el = this.$refs.drop.$refs.drop;
          if ($el === event.target || $el.contains(event.target)) {
            return;
          }
        }

        this.closer(event);
        return;
      }

      this.visible = false;
    },
    toggleVisible() {
      if (this.disabled) {
        return;
      }

      this.visible = !this.visible;
    },
    closer(event) {
      if (event) {
        event.preventDefault();
        event.stopPropagation();
      }

      this.visible = false;
    }
  },
};
</script>
