<script lang="ts" setup>
import { computed, ref, watch } from 'vue';

import {
  Button,
  Checkbox,
  Divider,
  Dropdown,
  Input,
  Menu,
  MenuItem,
  SubMenu,
} from 'ant-design-vue';

import MIcon from '#/components/icon/icon.vue';

import type { SortDirection } from '../types';

const props = defineProps<{
  col: number;
  title: string;
  left: number;
  width: number;
  top: number;
  active: boolean;
  sortDirection?: SortDirection | null;
  uniqueValues: string[];
  checkedValues?: string[];
  disabled?: boolean;
  isDark?: boolean;
  loadingValues?: boolean;
}>();

const emit = defineEmits<{
  sort: [direction: SortDirection];
  clearSort: [];
  clearFilter: [];
  open: [];
  'update:checkedValues': [values: string[] | undefined];
}>();

const open = ref(false);
const search = ref('');

const effectiveChecked = computed(() => {
  if (props.checkedValues === undefined) {
    return new Set(props.uniqueValues);
  }
  return new Set(props.checkedValues);
});

const filteredValues = computed(() => {
  const q = search.value.trim().toLowerCase();
  const list = props.uniqueValues;
  if (!q) return list.slice(0, 200);
  return list.filter((v) => v.toLowerCase().includes(q)).slice(0, 200);
});

const allChecked = computed(
  () =>
    props.uniqueValues.length > 0 &&
    props.uniqueValues.every((v) => effectiveChecked.value.has(v)),
);

const indeterminate = computed(() => {
  if (allChecked.value) return false;
  return props.uniqueValues.some((v) => effectiveChecked.value.has(v));
});

function toggleValue(value: string, checked: boolean) {
  const next = new Set(effectiveChecked.value);
  if (checked) next.add(value);
  else next.delete(value);
  emit('update:checkedValues', [...next]);
}

function toggleAll(checked: boolean) {
  if (checked) {
    emit('update:checkedValues', undefined);
  } else {
    emit('update:checkedValues', []);
  }
}

watch(open, (v) => {
  if (v) {
    emit('open');
  } else {
    search.value = '';
  }
});
</script>

<template>
  <div
    class="header-column-filter"
    :class="{ 'is-dark': isDark }"
    :style="{ left: `${left}px`, top: `${top}px`, width: `${width}px` }"
  >
    <Dropdown
      v-model:open="open"
      :trigger="['click']"
      placement="bottomRight"
      :disabled="disabled"
      :overlay-class-name="isDark ? 'sheet-header-filter-dropdown is-dark' : 'sheet-header-filter-dropdown'"
    >
      <Button
        class="filter-btn"
        :class="{
          'is-active': active,
          'is-sorted': !!sortDirection,
        }"
        size="small"
        type="text"
        @click.stop
      >
        <MIcon
          :icon="
            sortDirection === 'asc'
              ? 'ant-design:sort-ascending-outlined'
              : sortDirection === 'desc'
                ? 'ant-design:sort-descending-outlined'
                : 'ant-design:filter-outlined'
          "
        />
      </Button>
      <template #overlay>
        <div class="filter-panel" :class="{ 'is-dark': isDark }" @click.stop>
          <Menu mode="vertical">
            <SubMenu key="sort" title="排序">
              <MenuItem @click="emit('sort', 'asc')">升序</MenuItem>
              <MenuItem @click="emit('sort', 'desc')">降序</MenuItem>
              <MenuItem @click="emit('clearSort')">清除排序</MenuItem>
            </SubMenu>
            <MenuItem @click="emit('clearFilter')">清除筛选</MenuItem>
          </Menu>
          <Divider style="margin: 8px 0" />
          <Input
            v-model:value="search"
            allow-clear
            placeholder="搜索"
            size="small"
          />
          <div v-if="loadingValues" class="value-loading">加载中...</div>
          <div v-else class="value-list">
            <Checkbox
              :checked="allChecked"
              :indeterminate="indeterminate"
              @change="(e) => toggleAll(!!e.target.checked)"
            >
              全选
            </Checkbox>
            <Checkbox
              v-for="val in filteredValues"
              :key="val || '__empty__'"
              :checked="effectiveChecked.has(val)"
              @change="(e) => toggleValue(val, !!e.target.checked)"
            >
              {{ val || '(空白)' }}
            </Checkbox>
            <div
              v-if="uniqueValues.length > 200 && !search.trim()"
              class="value-hint"
            >
              值过多，请搜索缩小范围
            </div>
          </div>
        </div>
      </template>
    </Dropdown>
  </div>
</template>

<style scoped lang="scss">
.header-column-filter {
  position: absolute;
  height: 36px;
  pointer-events: none;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding-right: 2px;
}

.filter-btn {
  pointer-events: auto;
  width: 24px;
  height: 24px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #86909c;

  &.is-active,
  &.is-sorted {
    color: #1668dc;
    background: rgba(22, 104, 220, 0.08);
  }
}

.header-column-filter.is-dark .filter-btn {
  color: rgba(255, 255, 255, 0.45);

  &:hover {
    color: rgba(255, 255, 255, 0.85);
    background: rgba(255, 255, 255, 0.08);
  }

  &.is-active,
  &.is-sorted {
    color: #3c89e8;
    background: rgba(22, 104, 220, 0.25);
  }
}

.filter-panel {
  width: 240px;
  padding: 8px;
  background: #fff;
  border-radius: 8px;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);

  &.is-dark {
    background: #1f1f1f;
    border: 1px solid #424242;
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.45);

    :deep(.ant-menu) {
      background: transparent;
      color: rgba(255, 255, 255, 0.85);
    }

    :deep(.ant-menu-item),
    :deep(.ant-menu-submenu-title) {
      color: rgba(255, 255, 255, 0.85);

      &:hover {
        background: #303030 !important;
        color: rgba(255, 255, 255, 0.95);
      }
    }

    :deep(.ant-divider) {
      border-color: #424242;
    }

    :deep(.ant-input) {
      background: #141414;
      border-color: #424242;
      color: rgba(255, 255, 255, 0.85);

      &::placeholder {
        color: rgba(255, 255, 255, 0.35);
      }
    }

    :deep(.ant-input-clear-icon) {
      color: rgba(255, 255, 255, 0.45);
    }

    :deep(.ant-checkbox-wrapper) {
      color: rgba(255, 255, 255, 0.85);
    }

    .value-hint,
    .value-loading {
      color: rgba(255, 255, 255, 0.45);
    }
  }
}

.value-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-height: 240px;
  overflow: auto;
  margin-top: 8px;
}

.value-hint,
.value-loading {
  font-size: 12px;
  color: #86909c;
  padding: 4px 0;
}
</style>

<style lang="scss">
.sheet-header-filter-dropdown.is-dark {
  .ant-dropdown-menu {
    background: #1f1f1f;
    box-shadow: none;
  }
}
</style>
