<script setup lang="ts">
import type { IKnobProps } from '@interfaces/componentsProps';
import { computed, ref, type Ref } from 'vue';
import { convertThemeToColor } from '@helpers/common';
import {
  calcCenter,
  calcStart,
  calcNewValue,
  calcThemeColor,
  calcContainerSize,
} from '@stories/components/Knob/helpers';
import Button from '@stories/components/Button/Button.vue';

const props = withDefaults(defineProps<IKnobProps>(), {
  value: 0,
  min: 0,
  max: 5,
  step: 1,
  size: 'normal',
  buttons: false,
  theme: 'sky',
  darknessTheme: '500',
  negativeTheme: 'black',
  darknessNegativeTheme: '500',
  color: 'black',
  darknessColor: '500',
  background: 'white',
  showLabel: true,
  colorAsTheme: false,
  textBold: false,
});
const value = defineModel<number>('value', {
  default: 0,
}) as Ref<number>;

const isClickHold = ref<boolean>(false);

const degreesTotal = computed(() => 360 - 90);
const length = computed(() => props.max - props.min);
const center = computed(() => calcCenter(document.querySelector('.container')!));
const start = computed(() => calcStart(document.querySelector('.container')!));
const containerSize = computed(() => calcContainerSize(props.size));
const buttonSize = computed(() => {
  const size = props.size;
  return size === 'normal' || size === 'small' ? 'small' : size === 'large' ? 'large' : 'huge';
});
const textSize = computed(() => {
  if (props.fontSize) return props.fontSize;
  const size = props.size;
  return size === 'normal' ? '1.7rem' : size === 'small' ? '1.3rem' : size === 'large' ? '2.5rem' : '3.5rem';
});
const buttonPadding = computed(() => {
  const size = props.size;
  return size === 'normal'
    ? '0.3rem 0.5rem'
    : size === 'small'
      ? '0.2rem'
      : size === 'large'
        ? '0.5rem 0.75rem'
        : '0.7rem 1rem';
});
const buttonWidth = computed(() => `${+textSize.value.slice(0, -3) * 0.78}rem`);
const backgroundSize = computed(() => `${+containerSize.value.slice(0, -2) * 0.71}px`);
const themeColor = computed(() => calcThemeColor(props.colorGaps, props.theme, props.darknessTheme, value.value));
const textColor = computed(() => convertThemeToColor(props.color, props.darknessColor));
const backgroundCircle = computed(() => {
  const color = convertThemeToColor(
    props.negativeTheme ?? (props.theme === 'white' ? 'black' : props.theme === 'black' ? 'white' : props.theme),
    (!props.negativeTheme && props.theme === 'black') || props.negativeTheme === 'white'
      ? '500'
      : props.darknessNegativeTheme,
  );
  return `radial-gradient(circle at center, transparent 50%, ${color} 50%)`;
});
const conicGradient = computed(() => {
  const valueDeg = 225 + (value.value / length.value) * degreesTotal.value;
  if (valueDeg >= 360)
    return `conic-gradient(${themeColor.value} 0deg ${valueDeg % 360}deg, transparent ${valueDeg % 360}deg 225deg, ${themeColor.value} 225deg 360deg)`;
  return `conic-gradient(transparent 0deg 225deg, ${themeColor.value} 225deg ${valueDeg}deg, transparent ${valueDeg}deg 360deg)`;
});

const setNewValue = ($event: MouseEvent) => {
  value.value = calcNewValue(
    $event,
    center.value,
    start.value,
    degreesTotal.value,
    length.value,
    props.step,
    value.value,
  );
};
const onPointerDown = ($event: MouseEvent) => {
  isClickHold.value = true;
  setNewValue($event);
};
</script>

<template>
  <section
    @pointerdown.prevent="!buttons && onPointerDown($event)"
    @pointermove="isClickHold ? setNewValue($event) : ''"
    @pointerup="isClickHold = false"
    class="container containerSize"
  >
    <div class="background"></div>
    <span
      v-if="showLabel"
      class="count"
      :style="`color: ${colorAsTheme ? themeColor : textColor};
       font-weight: ${textBold ? 'bold' : 'medium'};
       font-size: ${textSize}`"
      >{{ textBefore ?? '' }}{{ value }}{{ textAfter ?? '' }}</span
    >
    <div class="circle containerSize">
      <div class="circle containerSize selected"></div>
    </div>
    <div v-if="buttons" class="buttons" :style="`gap: ${+textSize.slice(0, -3) * 3}px`">
      <Button
        @click="value++"
        :theme="negativeTheme"
        textColor="white"
        :size="buttonSize"
        label="+"
        textStyle="bold"
        :padding="buttonPadding"
        :width="buttonWidth"
      ></Button>
      <Button
        @click="value--"
        :theme="negativeTheme"
        textColor="white"
        :size="buttonSize"
        label="-"
        textStyle="bold"
        :padding="buttonPadding"
        :width="buttonWidth"
      ></Button>
    </div>
  </section>
</template>

<style scoped>
.container {
  position: relative;
}
.containerSize {
  width: v-bind(containerSize);
  height: v-bind(containerSize);
}
.circle {
  position: relative;
  border-radius: 50%;
  background: v-bind(backgroundCircle);
  clip-path: polygon(0 0, 0 100%, 50% 50%, 50% 50%, 100% 100%, 100% 0);
}
.selected {
  position: absolute;
  z-index: 3;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: v-bind(conicGradient);
}
.background {
  width: v-bind(backgroundSize);
  height: v-bind(backgroundSize);
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 4;
  background: v-bind(background);
  border-radius: 50%;
  transform: translate(-50%, -50%);
}
.count {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 5;
  transform: translate(-50%, -50%);
  user-select: none;
}
.buttons {
  display: flex;
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  z-index: 5;
}
</style>