<template>
  <view class="input-wrapper" :style="{ '--main-color': themeColor , '--bar-height' :barHeight , 'padding-bottom': dynamicBottom   }">
    <!-- 引用条 + 输入框：纵向 flex，引用条在上、输入框在下 -->
    <view class="input-bar-group">
      <!-- 引用回复条 -->
      <view v-if="isReplyValid" class="reply-bar" :style="{ '--dynamic-radius': dynamicRadius + 'rpx' }" @touchstart.prevent>
        <view class="reply-bar-inner">
          <view class="reply-text-wrap">
            <text class="reply-name">{{ replyDisplayName }}</text>
            <text class="reply-content">{{ replyDisplayContent }}</text>
          </view>
        </view>
      </view>
      <!-- 取消引用 -->
      <view v-if="isReplyValid" class="reply-seam" @touchstart.prevent="clearReplyRef">
        <view class="reply-seam-line" />
        <text class="reply-seam-text">取消引用</text>
      </view>

      <view 
        class="input-container" 
      :class="{ 
        'has-reply': isReplyValid,
        'mode-longpress': isLongPressing, 
        'mode-cancelling': isLongPressing && isCancelling 
      }"
      :style="{ 
        '--dynamic-radius': dynamicRadius + 'rpx',
        height: containerHeightRpx + 'rpx'
      }"
      @tap.stop
    >
      <!-- 左侧图标 -->
      <view 
        class="toggle-wrapper" 
        :class="{ 'node-hidden': isLongPressing, 'btn-press': leftBtnPressed }" 
        v-if="showLeftBtn" 
        @touchstart="leftBtnPressed = true"
        @touchend="leftBtnPressed = false"
        @touchcancel="leftBtnPressed = false"
        @tap="LeftButtonHandle"
      >
        <image class="toggle-icon" :src="LeftIcon" />
      </view>
      
      <!-- 中间触发区域 -->
      <view 
        class="input-area"
        @touchstart="handleTouchStart"
        @touchmove="handleTouchMove"
        @touchend="handleTouchEnd"
        @touchcancel="handleTouchEnd"
      >
        <textarea 
          class="input-text"
          :class="{ 'input-hidden': isLongPressing, 'is-scrollable': !shouldAutoHeight }"
          v-model="localInputText"
          :adjust-position="false" 
          :hold-keyboard="holdKeyboard"
          :focus="inputFocus"
          :confirm-type="confirmType"
          :auto-height="shouldAutoHeight"
          :fixed="true"
          :maxlength="-1"
          :style="{
            fontSize: textareaFontSize + 'rpx',
            ...(!shouldAutoHeight ? { height: MAX_TEXTAREA_HEIGHT + 'rpx' } : {})
          }"
          @focus="onFocus"
          @blur="onBlur"
          @confirm="handleConfirm"
          @linechange="onLineChange"
          :placeholder="placeholder" 
          placeholder-class="input-placeholder"
        />
        
        <!-- 长按激活时的遮罩/提示 -->
        <view v-if="isLongPressing" class="longpress-overlay">
          <text class="longpress-tip">
            {{ isCancelling ? cancelTip : longPressTip }}
          </text>
        </view>
      </view>

      <!-- 右侧按钮区域 -->
      <view 
        class="attachment-btn" 
        :class="{ 'is-send': hasText, 'node-hidden': isLongPressing, 'btn-press': rightBtnPressed }"  
        @touchstart.prevent="rightBtnPressed = true; handleRightBtnTap()"
        @touchend="rightBtnPressed = false"
        @touchcancel="rightBtnPressed = false"
      >
        <image class="icon send-icon" :src="sendIcon"></image>
        <image class="icon attachment-icon" :src="attachmentIcon"></image>
      </view>
    </view>
    </view>

    <!-- 悬浮面板 -->
    <floatpanel
      :visible="innerShowPanel" 
      :buttons="buttons"
      :height="panelHeight"
      :bottomOffset="panelBottomOffset"
      :horizontalPadding="panelPadding"
      @handleTap="onPanelSelect"
    >
      <template v-if="hasCustomPanel" #default>
        <slot name="panel-content"></slot>
      </template>
    </floatpanel>
    
    <!-- 遮罩层：点击空白处关闭面板 -->
    <view 
      v-if="innerShowPanel" 
      class="panel-mask" 
      @tap="setPanelVisible(false)"
    />
  </view>
</template>

<script setup>
import { ref, computed, nextTick, watch, useSlots , onMounted , onUnmounted } from 'vue'
import floatpanel from './floatPanel.vue'

const slots = useSlots()

const props = defineProps({
  // --- 内容与状态 ---
  modelValue: { type: String, default: '' }, // 支持 v-model 直接绑定文字内容
  showPanel: { type: Boolean, default: false }, // 支持 v-model:showPanel
  /** 引用回复：外部传入任意对象，内部仅要求包含 content(string) 与 Name/name；有效时才显示引用条，支持双向 */
  replyRef: { type: [Object, null], default: null },
  /** 外部控制的焦点状态 */
  focus: { type: Boolean, default: false },
  
  // --- 提示文字 ---
  placeholder: { type: String, default: '点击输入或按住说话....' },
  longPressTip: { type: String, default: '正在录音，上滑取消' },
  cancelTip: { type: String, default: '松开手指，取消发送' },
  
  // --- 样式配置 ---
  themeColor: { type: String, default: '#a846e6' },
  barHeight: { type: String, default: '80rpx' },
  padBottom: { type: String, default: '4rpx' },
  LeftIcon: { type: String, default: '/static/Mic.png' },
  sendIcon: { type: String, default: '/static/send.png' },
  attachmentIcon: { type: String, default: '/static/Attachment.png' },
  
  // --- 功能开关 ---
  showLeftBtn: { type: Boolean, default: true }, // 是否显示左侧图标
  
  // --- 面板配置 ---
  buttons: { type: Array },
  panelHeight: { type: String, default: '100rpx' },
  panelBottomOffset: { type: String, default: '10rpx' },
  panelPadding: { type: String, default: '15rpx' },
  
  // --- 交互参数 ---
  longPressDelay: { type: Number, default: 200}, // 长按判定时间(ms) -- 这个数值不建议高于500 高于会触发长按聚焦文字框
  cancelThreshold: { type: Number, default: 100 }, // 上滑取消判定距离(px)
  
  // --- 原生 Input 属性 ---
  adjustPosition: { type: Boolean, default: false },
  holdKeyboard: { type: Boolean, default: true },
  confirmType: { type: String, default: 'send' }
})

const emit = defineEmits([
  'update:modelValue', 
  'update:showPanel',
  'update:replyRef',
  'longPressStart', 
  'longPressEnd', 
  'longPressCancel', 
  'send', 
  'panelClick',
  'leftButtonClick',
  'focus',
  'blur',
	'keyboardHeightChange'
])

// --- 内部变量 ---
const inputFocus = ref(false)
const isLongPressing = ref(false) 
const isCancelling = ref(false)
const startY = ref(0)
const lastMoveY = ref(0) // 记录最后一次移动的 Y 坐标
const longPressTimer = ref(null)
const focusLock = ref(false)
const didTouchMove = ref(false) // 是否发生了滑动（用于区分点击聚焦 / 滑动松手）
const leftBtnPressed = ref(false)
const rightBtnPressed = ref(false)
const keyboardHeight = ref(0)

// 监听外部传入的 focus prop，立即同步以提高响应速度
watch(() => props.focus, (val) => {
	if (val !== inputFocus.value) {
		inputFocus.value = val
		// 如果外部设置为 false，触发 blur 事件
		if (!val) {
			emit('blur')
		}
	}
}, { immediate: true })

// 双向绑定输入框内容
const localInputText = ref(props.modelValue)
watch(() => props.modelValue, (val) => localInputText.value = val)
watch(localInputText, (val) => emit('update:modelValue', val))

// 双向绑定面板显示状态
const innerShowPanel = ref(props.showPanel)
watch(() => props.showPanel, (val) => innerShowPanel.value = val)
const setPanelVisible = (visible) => {
  innerShowPanel.value = visible
  emit('update:showPanel', visible)
}

// 引用回复：仅当包含 content(string) 与 Name/name 时视为有效
const isReplyValid = computed(() => {
  const r = props.replyRef
  if (!r || typeof r !== 'object') return false
  const hasContent = typeof r.content === 'string'
  const hasName = typeof (r.Name ?? r.name) === 'string'
  return hasContent && hasName
})
const replyDisplayName = computed(() => {
  if (!isReplyValid.value) return ''
  const r = props.replyRef
  return (r.Name ?? r.name) ?? ''
})
const replyDisplayContent = computed(() => {
  if (!isReplyValid.value) return ''
  const raw = props.replyRef?.content ?? ''
  const oneLine = String(raw).replace(/\s*[\r\n]+\s*/g, ' ').trim()
  return oneLine.length > 40 ? oneLine.slice(0, 40) + '…' : oneLine
})
const clearReplyRef = () => {
  emit('update:replyRef', null)
}

// 逻辑计算
const hasCustomPanel = computed(() => !!slots['panel-content'])
const hasText = computed(() => localInputText.value.trim().length > 0)

// 输入区高度(rpx)
const textareaHeightRpx = ref(68)

// 从 barHeight prop 解析出数值（去掉 'rpx' 后缀）
const PILL_HEIGHT = computed(() => {
  const heightStr = props.barHeight.replace('rpx', '')
  return parseInt(heightStr) || 80
})

// 字体大小跟随 barHeight 等比例缩放（默认 80rpx 对应 28rpx）
const textareaFontSize = computed(() => {
  const baseHeight = 80
  const baseFontSize = 28
  const ratio = PILL_HEIGHT.value / baseHeight
  return Math.round(baseFontSize * ratio)
})

const MAX_TEXTAREA_HEIGHT = 300  // textarea 超过此高度时变为可滚动
const MAX_HEIGHT = 16 + MAX_TEXTAREA_HEIGHT  // 容器最大高度 = 内边距 + textarea高度
const PILL_RADIUS = 50
const RECT_RADIUS = 36

// 当高度超过阈值时 - 输入区域变成可滚动
const shouldAutoHeight = computed(() => textareaHeightRpx.value < MAX_TEXTAREA_HEIGHT)

// 容器高度（rpx）
const containerHeightRpx = computed(() => {
  // 最小高度 = barHeight - padding (上下各6rpx = 12rpx)
  const minInnerH = PILL_HEIGHT.value - 12
  const innerH = Math.max(minInnerH, textareaHeightRpx.value)
  const h = 12 + innerH  // 上下 padding 各 6rpx
  return Math.min(MAX_HEIGHT, Math.max(PILL_HEIGHT.value, h))
})

const dynamicRadius = computed(() => {
  const containerH = containerHeightRpx.value
  const pillH = PILL_HEIGHT.value
  if (containerH <= pillH) return PILL_RADIUS
  if (containerH >= MAX_HEIGHT) return RECT_RADIUS
  return Math.round(PILL_RADIUS - (containerH - pillH) * (PILL_RADIUS - RECT_RADIUS) / (MAX_HEIGHT - pillH))
})

const dynamicBottom = computed(() => {
  if (keyboardHeight.value > 0) {
    // 键盘弹出时：直接使用键盘的物理像素高度 + 你自己的下边距
    return `calc(${keyboardHeight.value}px + ${props.padBottom})`
  } else {
    // 键盘收起时：回归底部，兼容全面屏小黑条
    return `calc(env(safe-area-inset-bottom) + ${props.padBottom})`
  }
})

const onLineChange = (e) => {
  let { height, heightRpx } = e.detail || {}
  // 部分平台只有 height(px)，需转换为 rpx
  if ((!heightRpx || heightRpx <= 0) && height > 0) {
    const winWidth = uni.getSystemInfoSync().windowWidth || 375
    heightRpx = Math.round(height * 750 / winWidth)
  }
  // if (heightRpx > 0) textareaHeightRpx.value = heightRpx
  if (heightRpx > 0) {
      textareaHeightRpx.value = heightRpx;
      // 触发高度变化事件，通知父组件滚动列表
      nextTick(() => {
        emit('heightChange');
      });
    }
}

// 清空时重置高度
watch(localInputText, (val) => {
  if (!val.trim()) {
    // 重置为 barHeight - padding (上下各6rpx = 12rpx)
    textareaHeightRpx.value = PILL_HEIGHT.value - 12
  }
})

// --- 事件处理 ---
const handleTouchStart = (e) => {
  didTouchMove.value = false
  if (focusLock.value || hasText.value || inputFocus.value) return
  const touchY = e.touches[0].clientY
  startY.value = touchY
  lastMoveY.value = touchY // 初始化为起始位置
  longPressTimer.value = setTimeout(() => {
    isLongPressing.value = true
    isCancelling.value = false
    uni.vibrateShort();
    emit('longPressStart');
  }, props.longPressDelay)
}

const handleTouchMove = (e) => {
  if (!isLongPressing.value) {
    didTouchMove.value = true // 发生滑动，touchend 时不要触发聚焦
    return // 不拦截，让 textarea 能正常滚动
  }
  e.preventDefault()
  const moveY = e.touches[0].clientY
  lastMoveY.value = moveY
  isCancelling.value = (startY.value - moveY > props.cancelThreshold)
}

const handleTouchEnd = () => {
  if (longPressTimer.value) {
    clearTimeout(longPressTimer.value)
    longPressTimer.value = null
  }

  if (isLongPressing.value) {
    const shouldCancel = (startY.value - lastMoveY.value > props.cancelThreshold)
    
    emit(shouldCancel ? 'longPressCancel' : 'longPressEnd')
    isLongPressing.value = false
    isCancelling.value = false
    focusLock.value = true
    setTimeout(() => { focusLock.value = false }, 200) // 减少锁定时间，提高响应速度
  } else {
    // 只有真正的点击（无滑动）才触发聚焦，滑动松手不触发
    // 优化：如果外部已经设置了 focus，或者没有滑动，则触发聚焦
    if (!focusLock.value && !didTouchMove.value) {
      // 如果外部传入的 focus 为 true，直接同步内部状态
      if (props.focus) {
        inputFocus.value = true
      } else if (!inputFocus.value) {
        // 只有在未聚焦时才触发聚焦
        nextTick(() => { 
          inputFocus.value = true
          emit('focus')
        })
      }
    }
    // 重置滑动标志
    didTouchMove.value = false
  }
}

const onFocus = () => { 
  inputFocus.value = true
  emit('focus');
}
const onBlur = () => { 
  inputFocus.value = false
  emit('blur'); // 触发 blur 事件，让父组件知道焦点已失去
}

const handleRightBtnTap = () => {
  if (hasText.value) {
    emit('send', { type: 'text', content: localInputText.value })
    localInputText.value = ''
  } else {
    setPanelVisible(!innerShowPanel.value)
  }
}

// 发送键
const handleConfirm = () => {
  if (hasText.value) {
    emit('send', { type: 'text', content: localInputText.value })
    localInputText.value = ''
  }
}

const onPanelSelect = (item) => { 
  emit('panelClick', item.button)//返回对应的button数据
  setTimeout(() => setPanelVisible(false), 150)
}

const LeftButtonHandle = () => {
  emit('leftButtonClick');
}

onMounted(() => {
  uni.onKeyboardHeightChange(res => {
    keyboardHeight.value = res.height;
    emit('keyboardHeightChange', res.height);
  });
});

onUnmounted(() => {
  uni.offKeyboardHeightChange();
});
</script>

<style lang="scss" scoped>
$paddingBottom : var(--paddingBottom);
$MainColor: var(--main-color);

.input-wrapper {
	width: 100%;
	box-sizing: border-box; 
	position: relative;
	flex-shrink: 0;
	z-index: 999;
	display: flex;
	flex-direction: column;
	align-items: center;
	padding: 0 12rpx;
	transition: padding-bottom 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94),
			  height 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

/* 引用条 + 输入框的纵向容器 */
.input-bar-group {
  display: flex;
  flex-direction: column;
  width: 100%;
  align-items: stretch;
}

/* 引用回复条*/
.reply-bar {
  width: 100%;
  box-sizing: border-box;
  background-color: rgba(38, 38, 38, 0.6);
  backdrop-filter: blur(20rpx);
  -webkit-backdrop-filter: blur(20rpx);
  border: 1px solid rgba(255, 255, 255, 0.05);
  border-bottom: none;
  border-radius: var(--dynamic-radius, 50rpx) var(--dynamic-radius, 50rpx) 0 0;
  margin-bottom: -1rpx;
  padding: 8rpx 10rpx 10rpx;
}
.reply-bar-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2rpx;
}
.reply-text-wrap {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2rpx;
}
/* Name */
.reply-name {
  font-size: 20rpx;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.42);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  width: 100%;
  text-align: center;
}
/* Content */
.reply-content {
  font-size: 28rpx;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.88);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  width: 100%;
  text-align: center;
  max-width: 100%;
}
/* 引用内容渐变线 */
.reply-seam-line {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 1px;
  background: linear-gradient(
    to right,
    transparent 0%,
    transparent 28%,
    rgba(255, 255, 255, 0.2) 48%,
    rgba(255, 255, 255, 0.2) 52%,
    transparent 72%,
    transparent 100%
  );
}
/* 接缝 + 「取消引用」文字 */
.reply-seam {
  position: relative;
  width: 100%;
  box-sizing: border-box;
  background-color: rgba(38, 38, 38, 0.6);
  backdrop-filter: blur(20rpx);
  -webkit-backdrop-filter: blur(20rpx);
  border-left: 1px solid rgba(255, 255, 255, 0.05);
  border-right: 1px solid rgba(255, 255, 255, 0.05);
  padding: 5rpx 10rpx 8rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}
.reply-seam-text {
  font-size: 22rpx;
  color: rgba(255, 255, 255, 0.4);
}

.input-container {
  display: flex; 
  box-sizing: border-box;
  align-items: center;
  width: 100%;
  min-height: var(--bar-height);
  max-height: 360rpx;
  background-color: rgba(38, 38, 38, 0.6);
  backdrop-filter: blur(20rpx);
  -webkit-backdrop-filter: blur(20rpx);
  border-radius: var(--dynamic-radius, 50rpx);
  padding-top: 6rpx;
  padding-bottom: 6rpx;
  padding-left: 6rpx;
  padding-right: 6rpx;
  border: 1px solid rgba(255, 255, 255, 0.05);
  /* 高度、圆角、背景色 带缓动过渡 */
  transition: height 0.28s cubic-bezier(0.25, 0.46, 0.45, 0.94), 
    border-radius 0.28s cubic-bezier(0.25, 0.46, 0.45, 0.94),
    background-color 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94),
    backdrop-filter 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94);
  overflow: hidden;

  &.has-reply {
    border-radius: 0 0 var(--dynamic-radius, 36rpx) var(--dynamic-radius, 36rpx);
  }
  &.mode-longpress {
    background-color: var(--main-color) !important;
    backdrop-filter: blur(20rpx);
    -webkit-backdrop-filter: blur(20rpx);
  }
  &.mode-cancelling {
    background-color: rgba(255, 77, 79, 0.8) !important;
    backdrop-filter: blur(20rpx);
    -webkit-backdrop-filter: blur(20rpx);
  }
}

/* 长按时两侧按钮的平滑缩小/隐藏（带过渡动效） */
.node-hidden {
  width: 0 !important;
  height: 0 !important;
  opacity: 0 !important;
  margin: 0 !important;
  padding: 0 !important;
  transform: scale(0);
  pointer-events: none;
}

.toggle-wrapper {
  height: calc(var(--bar-height) - 12rpx);
  width: calc(var(--bar-height) - 12rpx);
  aspect-ratio: 1;
  border-radius: 999rpx;
  background-color: $MainColor;
  display: flex;
  justify-content: center;
  align-items: center;  
  flex-shrink: 0;
  /* 按下缩放 + 长按隐藏时的缩小动效 */
  transition: width 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94),
    height 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94),
    opacity 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94),
    margin 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94),
    padding 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94),
    transform 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94);
  
  &.btn-press {
    transform: scale(0.92);
  }
  
  .toggle-icon {
    height: 70%;
    width: 70%;
  }
}

.input-area {
  flex: 1;
  margin: 0 8rpx;
  display: flex;
  align-items: center;
  position: relative;
  overflow: visible;
  min-width: 0;
  min-height: calc(var(--bar-height) - 12rpx);
  max-height: 300rpx;
  
  .input-placeholder {
    color: #999999; 
    font-weight: 400; 
  }
  
  .input-text {
    width: 100%;
    font-weight: 800;
    color: #ffffff;  
    transition: opacity 0.2s;
    line-height: 1.3;
    box-sizing: border-box;
    padding: 0;

    &.input-hidden {
      opacity: 0;
      visibility: hidden;
    }
    
    /* 超过最大高度后变为可滚动 */
    &.is-scrollable {
      overflow-y: auto !important;
    }
  }
}

.longpress-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  pointer-events: none;
  
  .longpress-tip {
    font-size: 30rpx;
    color: #ffffff;
    font-weight: bold;
  }
}

.attachment-btn {
  --offset: 6%;
  width: calc(var(--bar-height) - 12rpx);
  height: calc(var(--bar-height) - 12rpx);
  border-radius: 999rpx;
  background-color: rgba(255, 255, 255, 0.08);
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
  overflow: hidden;
  flex-shrink: 0;
  /* 按下缩放 + 长按隐藏时的缩小动效 + 主题色渐变 */
  transition: width 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94),
    height 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94),
    opacity 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94),
    margin 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94),
    padding 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94),
    transform 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94),
    background-color 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94),
    filter 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94);
  
  &.btn-press {
    transform: scale(0.92);
  }

  .icon {
    position: absolute;
    width: 50%;
    height: 50%;
    transition: all 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
  }

  .attachment-icon {
    opacity: 1;
    transform: rotate(0deg) scale(1);
  }

  .send-icon {
    opacity: 0;
    transform: rotate(-90deg) scale(0) translateX(var(--offset));
  }

  &.is-send {
    background-color: $MainColor; 
	filter: brightness(1.1); // 相对主要色变得亮一点
    
    .attachment-icon {
      opacity: 0;
      transform: rotate(90deg) scale(0);
    }
    
    .send-icon {
      opacity: 1;
      transform: rotate(0deg) scale(1) translateX(var(--offset));
    }
  }
}

.panel-mask {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 998;
}
</style>