<template>
  <div
    v-loading="effectiveProps.loading"
    class="ecp-collapse-container"
    :class="{
      'is-expanded': mergedExpanded,
      'is-ghost': effectiveProps.ghost,
      'is-header-clickable': canToggleByHeader,
    }"
    v-bind="wrapperProps"
  >
    <div v-if="showHeader" class="ecp-collapse-container__header" :class="effectiveProps.headerClass" :style="effectiveProps.headerStyle">
      <div class="ecp-collapse-container__header-main" @click="handleHeaderClick">
        <div v-if="$slots.title || effectiveProps.title" class="ecp-collapse-container__title-wrap">
          <slot name="title">
            <span class="ecp-collapse-container__title">{{ effectiveProps.title }}</span>
          </slot>
          <el-tooltip v-if="effectiveProps.helpMessage" placement="top" effect="dark">
            <template slot="content">
              <span v-if="Array.isArray(effectiveProps.helpMessage)">
                <div v-for="(msg, index) in effectiveProps.helpMessage" :key="index">{{ msg }}</div>
              </span>
              <span v-else>{{ effectiveProps.helpMessage }}</span>
            </template>
            <i class="el-icon-question ecp-collapse-container__help" />
          </el-tooltip>
        </div>
      </div>

      <div v-if="$slots.action || resolvedCanExpan" class="ecp-collapse-container__header-extra" @click.stop>
        <slot name="action" />
        <el-button
          v-if="resolvedCanExpan"
          type="text"
          class="ecp-collapse-container__toggle"
          @click.stop="toggleExpand"
        >
          {{ mergedExpanded ? effectiveProps.collapseButtonText : effectiveProps.expandButtonText }}
          <i class="el-icon-arrow-down" :class="{ 'is-expanded': mergedExpanded }" />
        </el-button>
      </div>
    </div>
    
    <el-collapse-transition>
      <div
        v-show="mergedExpanded"
        class="ecp-collapse-container__body"
        :class="effectiveProps.contentClass"
        :style="effectiveProps.contentStyle"
      >
        <slot />
      </div>
    </el-collapse-transition>
  </div>
</template>

<script setup lang="ts">
import { computed, ref, watch, useSlots } from 'vue'
import { useComponentSetting } from '../useComponentSetting'

interface CollapseContainerProps {
  title?: string
  loading?: boolean
  canExpan?: boolean
  canExpand?: boolean
  helpMessage?: string | string[]
  triggerWindowResize?: boolean
  expanded?: boolean
  defaultExpand?: boolean
  ghost?: boolean
  expandButtonText?: string
  collapseButtonText?: string
  wrapperProps?: Record<string, unknown>
  headerClass?: string
  headerStyle?: Record<string, string | number>
  contentClass?: string
  contentStyle?: Record<string, string | number>
}

const props = withDefaults(defineProps<CollapseContainerProps>(), {
  loading: false,
  canExpan: true,
  canExpand: undefined,
  triggerWindowResize: true,
  expanded: undefined,
  defaultExpand: true,
  ghost: false,
  expandButtonText: '展开',
  collapseButtonText: '收起',
  wrapperProps: () => ({}),
  headerClass: '',
  headerStyle: () => ({}),
  contentClass: '',
  contentStyle: () => ({}),
})

const emit = defineEmits<{
  (e: 'update:expanded', value: boolean): void
  (e: 'change', value: boolean): void
  (e: 'collapse'): void
  (e: 'expand'): void
}>()

const slots = useSlots()
const { mergeSettings } = useComponentSetting()

const innerExpanded = ref(props.expanded ?? props.defaultExpand)

const effectiveProps = computed(() => mergeSettings('CollapseContainer', { ...props }) as CollapseContainerProps)
const resolvedCanExpan = computed(() => effectiveProps.value.canExpand ?? effectiveProps.value.canExpan ?? true)
const isControlled = computed(() => effectiveProps.value.expanded !== undefined)
const mergedExpanded = computed(() => isControlled.value ? !!effectiveProps.value.expanded : innerExpanded.value)
const showHeader = computed(() => !!slots.title || !!slots.action || !!effectiveProps.value.title || !!effectiveProps.value.helpMessage || resolvedCanExpan.value)
const canToggleByHeader = computed(() => resolvedCanExpan.value)
const wrapperProps = computed(() => {
  const incoming = effectiveProps.value.wrapperProps ?? {}
  const wrapperClass = incoming.class
  const wrapperStyle = incoming.style
  const rest = { ...incoming }
  delete rest.class
  delete rest.style

  return {
    ...rest,
    class: wrapperClass,
    style: wrapperStyle,
  }
})

const triggerWindowResize = () => {
  if (!effectiveProps.value.triggerWindowResize || typeof window === 'undefined') return
  window.setTimeout(() => {
    window.dispatchEvent(new Event('resize'))
  }, 220)
}

const setExpanded = (value: boolean) => {
  if (!isControlled.value) {
    innerExpanded.value = value
  }
  emit('update:expanded', value)
  emit('change', value)
  if (value) emit('expand')
  else emit('collapse')
  triggerWindowResize()
}

const toggleExpand = () => {
  if (!resolvedCanExpan.value) return
  setExpanded(!mergedExpanded.value)
}

const handleHeaderClick = () => {
  if (!canToggleByHeader.value) return
  toggleExpand()
}

watch(() => props.expanded, (value) => {
  if (value !== undefined) {
    innerExpanded.value = value
  }
})

watch(() => props.defaultExpand, (value) => {
  if (props.expanded === undefined) {
    innerExpanded.value = value
  }
})

defineExpose({
  setExpanded,
  toggleExpand,
})
</script>

<style>
.ecp-collapse-container {
  background: #fff;
  border-radius: 14px;
  border: 1px solid #e8eef8;
  box-shadow: 0 10px 24px rgba(15, 45, 94, 0.06);
  overflow: hidden;
}

.ecp-collapse-container.is-ghost {
  border-color: transparent;
  box-shadow: none;
  background: transparent;
}

.ecp-collapse-container__header {
  min-height: 56px;
  padding: 0 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  border-bottom: 1px solid #eef3fb;
}

.ecp-collapse-container.is-ghost .ecp-collapse-container__header {
  padding-left: 0;
  padding-right: 0;
}

.ecp-collapse-container__header-main {
  min-width: 0;
  flex: 1;
  display: flex;
  align-items: center;
}

.ecp-collapse-container__title-wrap {
  min-width: 0;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.ecp-collapse-container__title {
  color: #1f2d3d;
  font-size: 16px;
  font-weight: 600;
  line-height: 1.4;
}

.ecp-collapse-container__help {
  color: #91a3b7;
  font-size: 14px;
}

.ecp-collapse-container__header-extra {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
  flex-shrink: 0;
}

.ecp-collapse-container__toggle {
  padding: 0;
  color: #2f6fd3;
}

.ecp-collapse-container__toggle i {
  margin-left: 6px;
  transition: transform 0.2s ease;
}

.ecp-collapse-container__toggle i.is-expanded {
  transform: rotate(180deg);
}

.ecp-collapse-container__body {
  padding: 20px;
  box-sizing: border-box;
}

.ecp-collapse-container.is-ghost .ecp-collapse-container__body {
  padding-left: 0;
  padding-right: 0;
}

.ecp-collapse-container.is-header-clickable .ecp-collapse-container__header-main {
  cursor: pointer;
}

@media (max-width: 768px) {
  .ecp-collapse-container__header {
    padding: 14px 16px;
    align-items: flex-start;
    flex-direction: column;
  }

  .ecp-collapse-container__header-extra {
    width: 100%;
    justify-content: space-between;
  }

  .ecp-collapse-container__body {
    padding: 16px;
  }
}
</style>
