<script lang="tsx">
import {
  computed,
  defineComponent,
  reactive,
  ref,
  type PropType,
  type Ref,
} from 'vue'
import DefaultButton from '../buttons/DefaultButton.vue'
import CheckBox from '../checkbox/ARKCheckbox.vue'
import BlackTooltip from '../tooltips/BlackTooltip.vue'
import {
  type ComputedColumn,
  type ComputedColumnInterface,
  type DraggedColumn,
} from './DefaultTableInterfaces'
import DefaultInput from '../inputs/default-input'

export default defineComponent({
  props: {
    columns: {
      type: Array as PropType<ComputedColumnInterface[]>,
      required: true,
    },
    onUpdate: {
      type: Function as PropType<() => void>,
      required: true,
    },
    isSmallSettingsButton: {
      type: Boolean,
      default: false,
    },
  },

  setup(props, { expose }) {
    const isOpened = ref(false)
    const draggedColumn: Ref<DraggedColumn | undefined> = ref(undefined)
    const hoveredOrder: Ref<number | undefined> = ref(undefined)
    const list: Ref<HTMLDivElement | null> = ref(null)
    const search = ref('')

    const computedColumns: Array<ComputedColumn> = reactive(
      props.columns.map((column) => ({
        source: column,

        draftOrder: column.order,
        draftVisibility: column.isVisible,
        draftHorizontalEyesight: column.horizontalEyesight,
      })),
    )

    /** watch(() => props.columns, () => {
      computedColumns = reactive(
        props.columns.map((column) => ({
          source: column,

          draftOrder: column.order,
          draftVisibility: column.isVisible,
        })),
      )
    }) */

    const toggleSettings = (val: boolean) => {
      isOpened.value = val
    }

    const toggleColumnVisibility = (
      column: ComputedColumn,
      val: (typeof column)['draftVisibility'],
    ) => {
      column.draftVisibility = val
    }

    const canSelectAll = computed(() => computedColumns.reduce((acc, c) => acc || !c.draftVisibility, false))
    const canDeselectAll = computed(() => computedColumns.some((item) => item.draftVisibility))

    const canReset = () => computedColumns.every(
      (c) => c.draftVisibility === c.source.visibleByDefault,
    )

    const canUpdate = computed(() => computedColumns.reduce(
      (acc, c) => acc
          || c.source.isVisible !== c.draftVisibility
          || c.source.order !== c.draftOrder
          || c.source.horizontalEyesight !== c.draftHorizontalEyesight,
      false,
    ))

    // кнопка disable, если не выбрано ни одно значение
    const disableUpdate = () => computedColumns.every((c) => !c.draftVisibility)

    const cancel = () => {
      computedColumns.forEach((column) => {
        column.draftVisibility = column.source.isVisible
        column.draftOrder = column.source.order
        column.draftHorizontalEyesight = column.source.horizontalEyesight
      })

      isOpened.value = false
    }

    const update = () => {
      computedColumns.forEach((column) => {
        column.source.isVisible = column.draftVisibility
        column.source.order = column.draftOrder
        column.source.horizontalEyesight = column.draftHorizontalEyesight
      })

      isOpened.value = false

      if (props.onUpdate) {
        props.onUpdate()
      }
    }

    const reset = () => {
      computedColumns.forEach((column) => {
        column.draftVisibility = column.source.visibleByDefault
          || typeof column.source.visibleByDefault === 'undefined'
        column.draftOrder = column.source.defaultOrder
      })

      if (props.onUpdate) {
        props.onUpdate()
      }
    }

    const toggleSelectAll = (value: boolean) => {
      computedColumns.forEach((column) => {
        if (!column.draftHorizontalEyesight) {
          column.draftVisibility = value
        }
      })
    }

    const sortedColumns = computed(() => [...computedColumns].sort((a, b) => a.draftOrder - b.draftOrder))

    const resetPaddings = (target?: HTMLDivElement) => {
      if (!target) return
      target.style.paddingBottom = '8px'
      target.style.paddingTop = '8px'
    }

    const onStartDrag = (column: DraggedColumn) => {
      draggedColumn.value = column
    }

    const onDrag = (e: DragEvent) => {
      const listEl = list.value as HTMLDivElement

      if (e.pageY > listEl.getBoundingClientRect().bottom - 30) {
        listEl.scrollTop += 1
      } else if (e.pageY < listEl.getBoundingClientRect().top + 30) {
        listEl.scrollTop -= 1
      }
    }

    const onDragover = (e: DragEvent, column: DraggedColumn, target?: HTMLDivElement) => {
      e.preventDefault()
      if (!target) return
      const bounding = target.getBoundingClientRect()
      const offset = bounding.y + (bounding.height / 2)
      if (e.clientY - offset > 0) {
        target.style.paddingBottom = '36px'
        target.style.paddingTop = '8px'
        hoveredOrder.value = column.draftOrder + 0.5
      } else {
        target.style.paddingTop = '36px'
        target.style.paddingBottom = '8px'
        hoveredOrder.value = column.draftOrder - 0.5
      }
    }

    const onStopDrag = (target?: HTMLDivElement) => {
      hoveredOrder.value = undefined
      draggedColumn.value = undefined
      resetPaddings(target)
    }

    const onDragLeave = (target?: HTMLDivElement) => {
      hoveredOrder.value = undefined
      resetPaddings(target)
    }

    const onDrop = (e: DragEvent, target?: HTMLDivElement) => {
      e.preventDefault()
      resetPaddings(target)
      if (!draggedColumn.value || (typeof hoveredOrder.value === 'undefined')) return
      draggedColumn.value.draftOrder = hoveredOrder.value
      sortedColumns.value.forEach((c, i) => { c.draftOrder = i })
    }

    expose({
      columns: computedColumns,
      toggleColumnVisibility,
      update,
    })

    return () => {
      const fixedColumns = sortedColumns.value.filter((column) => column.draftHorizontalEyesight === true)
      const regularColumns = sortedColumns.value.filter((column) => column.draftHorizontalEyesight !== true)

      const lastFixedColumn = fixedColumns[fixedColumns.length - 1]

      const renderColumn = (column: ComputedColumn) => {
        const elRef = ref<HTMLDivElement>()
        const isFixed = column.draftHorizontalEyesight
        const isLastFixed = isFixed && column === lastFixedColumn

        return (
          <div
            ref={elRef}
            onClick={() => { if (!isFixed) toggleColumnVisibility(column, !column.draftVisibility) }}
            onDrop={(e) => onDrop(e, elRef.value)}
            onDrag={onDrag}
            onDragstart={() => onStartDrag(column)}
            onDragend={() => onStopDrag(elRef.value)}
            onDragover={(e) => onDragover(e, column, elRef.value)}
            onDragleave={() => onDragLeave(elRef.value)}
            draggable={!isFixed}
            class={`ark-ui-table-setting-item
              ${column === draggedColumn.value ? 'is-dragged' : ''}
              ${isFixed ? 'fixed' : ''}
              ${isLastFixed ? 'last-fixed' : ''}`
            }
          >
            <div class="ark-ui-table-setting-item-icons">
              <div class="ark-ui-table-setting-item-icon"/>

              <CheckBox
                class="ark-ui-table-setting-item-checkbox"
                modelValue={column.draftVisibility}
                onValueChange={() => {
                  // do nothing
                }}
                isDisabled={isFixed}
              />
            </div>

            <div class="ark-ui-table-setting-item-text">{column.source.name}</div>

            {column.draftVisibility && (
              <BlackTooltip
                class="ark-ui-table-setting-push-pin-icon-wrapper"
                text={`${isFixed ? 'Открепить' : 'Закрепить'} столбец`}
                positionCorrectingX={48}
                positionCorrectingY={8}
                left={true}
              >
                <div
                  class="ark-ui-table-setting-push-pin-icon"
                  onClick={(event) => {
                    event.stopPropagation()
                    column.draftHorizontalEyesight = !column.draftHorizontalEyesight
                  }}
                />
              </BlackTooltip>
            )}
          </div>
        )
      }

      const columns = [...fixedColumns, ...regularColumns]
        // eslint-disable-next-line arrow-body-style
        .filter((item) => {
          return search.value
            ? item.source.name.toLowerCase().includes(search.value.toLowerCase())
            : true
        })
        .map(renderColumn)

      return (
        <BlackTooltip
          class="ark-ui-table-button-settings-wrapper"
          text="Настроить показ таблицы"
          left={true}
          positionCorrectingY={4}
        >
          <div
            onClick={() => toggleSettings(!isOpened.value)}
            class={`
              ark-ui-table-button-settings
              ${isOpened.value ? 'opened' : ''}
              ${props.isSmallSettingsButton ? 'small' : ''}
            `}
          />

          <div
            class="ark-ui-table-settings-body"
            style={isOpened.value ? 'display: block;' : 'display: none;'}
          >
            <div class="ark-ui-table-settings-top">
              <div class="ark-ui-table-settings-search">
                <DefaultInput
                  isResettable={!!search.value.length}
                  modelValue={search.value}
                  placeholder="Найти в списке"
                  leftSlot={() => (
                    <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                      {/* eslint-disable-next-line max-len */}
                      <path fill-rule="evenodd" clip-rule="evenodd" d="M10.8744 11.5815C9.82908 12.4664 8.47685 13 7 13C3.68629 13 1 10.3137 1 7C1 3.68629 3.68629 1 7 1C10.3137 1 13 3.68629 13 7C13 8.47685 12.4664 9.82908 11.5815 10.8744L13.8536 13.1464C14.0488 13.3417 14.0488 13.6583 13.8536 13.8536C13.6583 14.0488 13.3417 14.0488 13.1464 13.8536L10.8744 11.5815ZM12 7C12 9.76142 9.76142 12 7 12C4.23858 12 2 9.76142 2 7C2 4.23858 4.23858 2 7 2C9.76142 2 12 4.23858 12 7Z" fill="#27282E"/>
                    </svg>
                  )}
                  onValueChange={(value) => { search.value = value }}
                />
              </div>

              <div class="ark-ui-table-settings-selection">
                <div>
                  <div
                    class={`ark-ui-table-setting-top ${!canSelectAll.value || !columns.length ? 'is-disabled' : ''}`}
                    onClick={() => toggleSelectAll(true)}
                  >
                    Выбрать все
                  </div>
                  <div
                    class={`ark-ui-table-setting-top ${!canDeselectAll.value || !columns.length ? 'is-disabled' : ''}`}
                    onClick={() => toggleSelectAll(false)}
                  >
                    Сбросить
                  </div>
                </div>

                <div>
                  <div
                    class={`ark-ui-table-setting-top ${canReset() || !columns.length ? 'is-disabled' : ''}`}
                    onClick={reset}
                  >
                    По умолчанию
                  </div>
                </div>
              </div>
            </div>

            <div class="ark-ui-table-setting-list-wrapper">
              <div ref={list} class="ark-ui-table-setting-list">
                {columns.length ? columns : (
                  <div class="ark-ui-table-setting-noResult">

                    <div class="ark-ui-table-setting-noResult-image" />
                    <div class="ark-ui-table-setting-noResult-text">По вашему запросу ничего не найдено</div>

                  </div>
                )}
              </div>
            </div>

            <div class="ark-ui-table-settings-bottom">
              <DefaultButton
                onClick={cancel}
                label="Отменить"
                size="S"
                type="secondary"
              />
              <DefaultButton
                onClick={update}
                label="Применить"
                size="S"
                isDisabled={!canUpdate.value || disableUpdate()}
              />
            </div>
          </div>
        </BlackTooltip>
      )
    }
  },
})
</script>

<style lang="scss" scoped>
@import '../../styles/variables.scss';

$padding: 16px;

.ark-ui-table-button-settings {
  height: 40px;
  width: 40px;
  cursor: pointer;
  background: url(./assets/icon-grip.svg) center center no-repeat;
  border: 1px solid #d3d5e5;
  border-radius: 4px;
  box-sizing: border-box;

  &-wrapper {
    position: relative;
  }

  &.small {
    height: 32px;
    width: 32px;
  }

  &.opened,
  &:hover {
    border-color: #a3a7b9;
  }
}

.ark-ui-table-settings {
  &-body {
    position: absolute;
    top: 42px;
    right: 0;
    background: white;
    border-radius: 4px;
    box-shadow: 0 8px 16px rgba(75, 77, 89, 0.08);
    width: 320px;
    box-sizing: border-box;
    z-index: ($dropdown + 1);
  }

  &-top {
    gap: 20px;
    display: flex;
    flex-direction: column;

    padding: $padding;
  }

  &-search {
    height: 32px;

    &:deep(.ark-ui-input) {
      height: 32px;
    }
  }

  &-selection {
    display: flex;
    align-items: center;
    justify-content: space-between;

    & > * {
      display: flex;
      column-gap: 16px;
    }
  }

  &-bottom {
    padding: $padding;
    display: grid;
    column-gap: 8px;
    grid-template-columns: 1fr 1fr;

    &:deep(.ark-ui-button-wrapper) {
      .ark-ui-button {
        min-width: 140px;
      }
    }
  }
}

.ark-ui-table-setting {
  &-top {
    color: #3a84ff;
    cursor: pointer;
    font-size: 14px;
    transition: 0.1s;

    &.is-disabled {
      cursor: default;
      color: #d3d5e5;
    }
  }

  &-list {
    max-height: 224px;
    overflow-y: scroll;

    &-wrapper {
      padding-right: $padding;
      .ark-ui-table-setting-item-checkbox {
        margin-top: 0;
      }
    }

    &::-webkit-scrollbar {
      width: 4px;
      background: #f6f6fa;
    }

    &::-webkit-scrollbar-thumb {
      background: #a3a7b9;
      border-radius: 50px;
    }
  }

  &-noResult {
    width: 100%;
    height: 224px;

    display: flex;
    align-items: center;
    flex-direction: column;
    justify-content: center;

    &-image {
      width: 100px;
      height: 100px;

      background: url(./assets/search.svg) center center no-repeat;
    }

    &-text {
      color: #585B69;
      font-size: 14px;
    }
  }

  &-item {
    color: #585b69;
    cursor: move;
    transition: 0.4s;
    padding: 8px;
    padding-left: 5px;
    display: flex;
    align-items: flex-start;
    justify-content: left;
    font-size: 14px;
    font-weight: 400;
    line-height: 16px;

    &-icons {
      display: flex;
      align-items: center;
    }

    &-icon {
      width: 6px;
      height: 10px;
      margin-right: 7px;
      transition: 0.4s;
      background-image: url('../tables/assets/drag-and-drop-dots.svg');
      background-repeat: no-repeat;
    }

    &-text {
      margin-left: 10px;
      word-break: break-word;
    }

    &-checkbox {
      cursor: pointer;
    }

    &.is-dragged {
      background-color: #f0f1f7;
    }

    .ark-ui-table-setting-push-pin-icon-wrapper {
      margin-left: auto;
    }

    .ark-ui-table-setting-push-pin-icon {
      opacity: 0;
      width: 16px;
      height: 16px;
      background-image: url('../tables/assets/push-pin.svg');
      background-repeat: no-repeat;
      transition: 0.3s;
      cursor: pointer;

      &:hover {
        background-image: url('../tables/assets/dark-push-pin.svg');
      }
    }

    &:hover {
      background-color: #f6f6fa;

      .ark-ui-table-setting-push-pin-icon {
        opacity: 1;
      }
    }
  }
}

.fixed {
  .ark-ui-table-setting-item-icon {
    background-image: none;
  }

  &.last-fixed {
    border-bottom: 1px solid #F6F6FA;
  }

  &:hover, .ark-ui-checkbox {
    cursor: default;
  }
}
</style>
