<template>
  <m-card :title="panelTitle" :width="width" :height="panelHeight">
    <div
      class="layer-panel"
      :class="{
        'is-legend-only': legendOnly,
        'is-compact': compact,
        'is-without-legend': !showLegend,
      }"
    >
      <div v-if="!legendOnly" class="layer-panel-list">
        <button
          v-for="layer in panelLayers"
          :key="layer.key"
          class="layer-panel-item"
          :class="{
            'is-active': isLayerActive(layer.key),
            'is-checked': isLayerActive(layer.key),
          }"
          type="button"
          @mousedown.prevent
          @click="handleLayerClick($event, layer.key)"
        >
          <span>{{ layer.name }}</span>
          <i></i>
        </button>
        <button
          v-for="layer in panelOverlayLayers"
          :key="layer.key"
          class="layer-panel-item is-overlay"
          :class="{
            'is-active': isOverlayActive(layer.key),
            'is-checked': isOverlayActive(layer.key),
          }"
          type="button"
          @mousedown.prevent
          @click="handleOverlayClick($event, layer.key)"
        >
          <span>{{ layer.name }}</span>
          <i></i>
        </button>
        <div v-if="!panelLayers.length && !panelOverlayLayers.length" class="layer-panel-empty">暂无图层配置</div>
      </div>

      <div v-if="showLegend" class="layer-panel-legend">
        <div class="layer-panel-section-title">图例</div>
        <div
          v-if="panelLegends.length"
          class="layer-panel-legend-grid"
          :class="{ 'is-single': legendSingle }"
        >
          <button
            v-for="item in panelLegends"
            :key="item.key || item.name"
            class="layer-panel-legend-row"
            :class="{
              'is-selected': isLegendItemSelectable(item) && item.key === selectedLegendKey,
              'is-checkable': isLegendItemSelectable(item),
              'is-disabled': !isLegendItemSelectable(item),
            }"
            type="button"
            :disabled="!isLegendItemSelectable(item)"
            :title="item.name"
            @mousedown.prevent
            @click="handleLegendClick($event, item)"
          >
            <span
              class="legend-swatch"
              :style="{
                backgroundColor: item.fillColor,
                borderColor: item.strokeColor || item.fillColor,
              }"
            ></span>
            <span class="legend-name">{{ item.name }}</span>
            <i v-if="isLegendItemSelectable(item)" class="legend-check"></i>
          </button>
        </div>
        <div v-else class="layer-panel-empty is-legend">暂无图例</div>
      </div>
    </div>
  </m-card>
</template>

<script setup>
import { computed } from "vue"
import mCard from "@/components/mCard/index.vue"
import { getLayersByTopic } from "@/config/layers"

const props = defineProps({
  topicKey: {
    type: String,
    required: true,
  },
  modelValue: {
    type: [String, Array],
    default: "",
  },
  legends: {
    type: Array,
    default: () => [],
  },
  selectedLegendKey: {
    type: String,
    default: "",
  },
  height: {
    type: Number,
    default: 0,
  },
  width: {
    type: Number,
    default: 248,
  },
  layers: {
    type: Array,
    default: null,
  },
  overlayLayers: {
    type: Array,
    default: () => [],
  },
  overlayKeys: {
    type: Array,
    default: () => [],
  },
  legendOnly: {
    type: Boolean,
    default: false,
  },
  multiple: {
    type: Boolean,
    default: false,
  },
  compact: {
    type: Boolean,
    default: false,
  },
  showLegend: {
    type: Boolean,
    default: true,
  },
})

const emit = defineEmits(["update:modelValue", "update:selectedLegendKey", "update:overlayKeys"])

const panelLayers = computed(() => Array.isArray(props.layers) ? props.layers : getLayersByTopic(props.topicKey))
const panelOverlayLayers = computed(() => Array.isArray(props.overlayLayers) ? props.overlayLayers : [])
const panelLegends = computed(() => Array.isArray(props.legends) ? props.legends : [])
const selectedLayerKeys = computed(() => {
  if (Array.isArray(props.modelValue)) return props.modelValue.map(String).filter(Boolean)
  return props.modelValue ? [String(props.modelValue)] : []
})
const selectedOverlayKeys = computed(() => Array.isArray(props.overlayKeys) ? props.overlayKeys.map(String).filter(Boolean) : [])
const legendSelectable = computed(() => panelLegends.value.filter(isSelectableLegend).length > 1)
const legendSingle = computed(() => panelLegends.value.length === 1)
const panelTitle = computed(() => {
  if (props.legendOnly) return "图例"
  return props.compact ? "图层" : "图层控制"
})
const compactPanelHeight = computed(() => {
  const layerCount = props.legendOnly ? 0 : panelLayers.value.length + panelOverlayLayers.value.length
  const layerRows = layerCount
  const legendRows = props.showLegend ? Math.ceil(panelLegends.value.length / 2) : 0
  const layerArea = layerRows ? layerRows * 34 + Math.max(0, layerRows - 1) * 5 : 30
  const legendArea = props.showLegend ? (panelLegends.value.length ? 30 + Math.max(28, legendRows * 28) : 28) : 0
  const minHeight = props.showLegend ? 172 : 108
  return Math.max(minHeight, Math.min(430, 72 + layerArea + legendArea))
})
const panelHeight = computed(() => {
  if (props.compact) return props.height || compactPanelHeight.value
  if (props.height) return props.height
  return 430
})

function handleLayerClick(event, layerKey) {
  event.currentTarget?.blur?.()
  if (props.multiple) {
    const nextKeys = new Set(selectedLayerKeys.value)
    if (nextKeys.has(layerKey)) nextKeys.delete(layerKey)
    else nextKeys.add(layerKey)
    emit("update:modelValue", Array.from(nextKeys))
    return
  }
  emit("update:modelValue", props.modelValue === layerKey ? "" : layerKey)
}

function isLayerActive(layerKey) {
  return selectedLayerKeys.value.includes(String(layerKey))
}

function handleOverlayClick(event, layerKey) {
  event.currentTarget?.blur?.()
  const nextKeys = new Set(selectedOverlayKeys.value)
  if (nextKeys.has(layerKey)) nextKeys.delete(layerKey)
  else nextKeys.add(layerKey)
  emit("update:overlayKeys", Array.from(nextKeys))
}

function isOverlayActive(layerKey) {
  return selectedOverlayKeys.value.includes(String(layerKey))
}

function handleLegendClick(event, item) {
  event.currentTarget?.blur?.()
  if (!isLegendItemSelectable(item)) return
  emit("update:selectedLegendKey", props.selectedLegendKey === item.key ? "" : item.key)
}

function isSelectableLegend(item) {
  if (item?.selectable === false) return false
  return Boolean(item?.key && (item.cqlFilter || item.rankingValueKey))
}

function isLegendItemSelectable(item) {
  return legendSelectable.value && isSelectableLegend(item)
}
</script>

<style lang="scss">
.layer-panel {
  display: grid;
  grid-template-rows: minmax(150px, 210px) minmax(0, 1fr);
  gap: 12px;
  height: 100%;
  box-sizing: border-box;
  padding: 12px 12px 14px;
  overflow: hidden;

  &.is-legend-only {
    grid-template-rows: minmax(0, 1fr);
    gap: 0;
    padding: 10px 12px 12px;

    .layer-panel-legend {
      padding-top: 0;
      border-top: 0;
    }

    .layer-panel-section-title {
      display: none;
    }

    .layer-panel-legend-grid {
      grid-template-columns: repeat(2, minmax(0, 1fr));
      justify-content: stretch;
      gap: 8px;
      max-height: 100%;
      padding-right: 0;
      overflow: hidden;

      &.is-single {
        grid-template-columns: minmax(0, 1fr);
      }
    }

    .layer-panel-legend-row {
      min-height: 28px;
      padding: 4px 2px;
    }
  }

  &.is-without-legend {
    grid-template-rows: auto;
    gap: 0;
  }

  &.is-compact {
    grid-template-rows: auto auto;
    align-content: start;
    gap: 10px;
    padding: 8px 10px 10px;

    &.is-without-legend {
      grid-template-rows: auto;
      gap: 0;
    }

    .layer-panel-list {
      grid-template-columns: minmax(0, 1fr);
      grid-auto-rows: 34px;
      gap: 5px 7px;
      padding-right: 4px;
      overflow-y: auto;
    }

    .layer-panel-item {
      height: 34px;
      flex-basis: 34px;
      padding: 0 9px;
      font-size: 12px;
    }

    .layer-panel-legend {
      padding-top: 9px;
    }

    .layer-panel-section-title {
      margin-bottom: 7px;
      font-size: 12px;
      line-height: 16px;

      &::before {
        top: 4px;
      }
    }

    .layer-panel-legend-grid {
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 6px 7px;
      max-height: none;
      padding-right: 0;
      overflow: visible;

      &.is-single {
        grid-template-columns: minmax(0, 1fr);
      }
    }

    .layer-panel-legend-row {
      grid-template-columns: 20px minmax(0, 1fr);
      align-items: center;
      min-height: 26px;
      padding: 3px 0;

      &.is-checkable {
        grid-template-columns: 20px minmax(0, 1fr) 14px;
      }
    }

    .legend-swatch,
    .legend-check {
      justify-self: center;
      margin-top: 0;
    }

    .legend-name {
      display: block;
      overflow: hidden;
      line-height: 16px;
      white-space: nowrap;
      text-overflow: ellipsis;
      -webkit-line-clamp: unset;
    }
  }

  &-list {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-auto-rows: 27px;
    align-content: start;
    gap: 7px 8px;
    min-height: 0;
    padding-right: 4px;
    overflow-y: auto;
  }

  &-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    box-sizing: border-box;
    height: 27px;
    flex: 0 0 27px;
    padding: 0 9px;
    border: 1px solid rgba(48, 220, 255, 0.22);
    background: rgba(3, 20, 32, 0.58);
    color: rgba(255, 255, 255, 0.74);
    font-size: 12px;
    cursor: pointer;

    span {
      min-width: 0;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    i {
      width: 8px;
      height: 8px;
      border: 1px solid rgba(255, 255, 255, 0.42);
      border-radius: 50%;
    }

    &.is-active {
      color: #fff;
      border-color: rgba(48, 220, 255, 0.7);
      background: linear-gradient(90deg, rgba(21, 121, 130, 0.52), rgba(3, 20, 32, 0.78));
    }

    &.is-checked {
      i {
        border-color: #30dcff;
        background: #30dcff;
        box-shadow: 0 0 12px rgba(48, 220, 255, 0.88);
      }
    }

    &.is-checked:not(.is-active) {
      color: rgba(255, 255, 255, 0.88);
      border-color: rgba(48, 220, 255, 0.42);
      background: rgba(3, 20, 32, 0.72);
    }

    &.is-overlay {
      i {
        border-radius: 1px;
      }

      &.is-checked i::after {
        content: "";
        display: block;
        width: 4px;
        height: 2px;
        margin: 2px 0 0 1px;
        border-left: 1px solid #08202d;
        border-bottom: 1px solid #08202d;
        transform: rotate(-45deg);
      }
    }
  }

  &-legend {
    min-height: 0;
    padding-top: 9px;
    border-top: 1px solid rgba(48, 220, 255, 0.18);
    overflow: visible;
  }

  &-section-title {
    position: relative;
    margin-bottom: 7px;
    padding-left: 10px;
    color: rgba(219, 249, 255, 0.9);
    font-size: 13px;
    font-weight: 600;
    line-height: 16px;

    &::before {
      content: "";
      position: absolute;
      left: 0;
      top: 4px;
      width: 4px;
      height: 8px;
      background: #30dcff;
      box-shadow: 0 0 10px rgba(48, 220, 255, 0.7);
    }
  }

  &-legend-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    justify-content: stretch;
    align-content: start;
    gap: 7px 8px;
    max-height: calc(100% - 24px);
    padding-right: 4px;
    overflow-y: auto;

    &.is-single {
      grid-template-columns: minmax(0, 1fr);
    }
  }

  &-legend-row {
    display: grid;
    grid-template-columns: 15px minmax(0, 1fr);
    align-items: start;
    column-gap: 6px;
    min-width: 0;
    min-height: 22px;
    padding: 3px 2px;
    border: 1px solid transparent;
    background: transparent;
    color: inherit;
    text-align: left;
    cursor: pointer;

    &:disabled {
      opacity: 1;
    }

    &.is-checkable {
      grid-template-columns: 15px minmax(0, 1fr) 12px;
    }

    &.is-selected {
      border-color: rgba(48, 220, 255, 0.42);
      background: rgba(48, 220, 255, 0.08);

      .legend-check {
        border-color: #30dcff;
        background: #30dcff;
        box-shadow: 0 0 10px rgba(48, 220, 255, 0.76);

        &::after {
          opacity: 1;
        }
      }
    }

    &.is-disabled {
      cursor: default;
    }
  }

  .legend-swatch {
    width: 15px;
    height: 10px;
    margin-top: 3px;
    border: 1px solid;
    box-shadow: 0 0 12px rgba(48, 220, 255, 0.18);
  }

  .legend-name {
    display: -webkit-box;
    min-width: 0;
    color: rgba(255, 255, 255, 0.82);
    font-size: 12px;
    line-height: 14px;
    overflow: hidden;
    word-break: break-all;
    white-space: normal;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
  }

  .legend-check {
    position: relative;
    width: 11px;
    height: 11px;
    margin-top: 2px;
    border: 1px solid rgba(255, 255, 255, 0.4);
    border-radius: 2px;

    &::after {
      content: "";
      position: absolute;
      left: 3px;
      top: 1px;
      width: 3px;
      height: 6px;
      border: solid rgba(3, 20, 32, 0.95);
      border-width: 0 1px 1px 0;
      opacity: 0;
      transform: rotate(45deg);
    }
  }

  &-empty {
    color: rgba(255, 255, 255, 0.52);
    line-height: 48px;
    text-align: center;

    &.is-legend {
      line-height: 28px;
    }
  }

  &-list,
  &-legend-grid {
    scrollbar-width: thin;
    scrollbar-color: rgba(48, 220, 255, 0.42) rgba(48, 220, 255, 0.08);

    &::-webkit-scrollbar {
      width: 4px;
    }

    &::-webkit-scrollbar-thumb {
      background: rgba(48, 220, 255, 0.42);
    }

    &::-webkit-scrollbar-track {
      background: rgba(48, 220, 255, 0.08);
    }
  }
}
</style>
