<template>
  <div v-if="visible" class="modal-overlay" @click.self="handleCancel">
    <div class="modal-content large">
      <div class="modal-header">
        <h3 class="modal-title">{{ title }}</h3>
        <button class="modal-close" @click="handleCancel">✕</button>
      </div>
      
      <div class="modal-body">
        <div class="user-selector">
          <!-- 左侧：可选人员 -->
          <div class="selector-panel">
            <div class="panel-header">
              <h4 class="panel-title">{{ leftTitle }}</h4>
              <span class="panel-count">
                {{ usePagination && totalElements > 0 ? `${availableList.length}/${totalElements}` : `${availableList.length}` }} 人
              </span>
            </div>
            <div class="panel-search">
              <input 
                v-model="searchAvailable"
                type="text"
                placeholder="搜索人员..."
                class="search-input-small"
              />
            </div>
            <div class="panel-body left-panel">
              <div class="user-list">
                <div
                  v-for="user in filteredAvailable"
                  :key="user.id"
                  class="user-item"
                  :class="{ selected: user.id && selectedAvailable.includes(user.id) }"
                  @click="user.id && toggleAvailable(user.id)"
                  @dblclick="user.id && moveToTarget(user.id)"
                >
                  <input
                    type="checkbox"
                    :checked="!!(user.id && selectedAvailable.includes(user.id))"
                    @click.stop="user.id && toggleAvailable(user.id)"
                  />
                  <span class="user-name">{{ user.username }}</span>
                  <span class="user-dept" v-if="user.deptName">({{ user.deptName }})</span>
                </div>
                
                <!-- 加载更多提示 -->
                <div v-if="usePagination && loadingMore" class="loading-more">
                  <div class="loading-spinner-small"></div>
                  <span>加载中...</span>
                </div>
                <div v-if="usePagination && !hasMore && availableList.length > 0" class="no-more">
                  已加载全部数据
                </div>
              </div>
            </div>
          </div>

          <!-- 中间：操作按钮 -->
          <div class="selector-actions">
            <button 
              class="action-btn"
              @click="moveSelectedToTarget"
              :disabled="selectedAvailable.length === 0"
              :title="mode === 'add' ? '添加选中' : '删除选中'"
            >
              <span class="arrow">→</span>
              <span class="btn-text">{{ mode === 'add' ? '添加' : '删除' }}</span>
            </button>
            <button 
              class="action-btn"
              @click="moveAllToTarget"
              :disabled="availableList.length === 0"
              :title="mode === 'add' ? '全部添加' : '全部删除'"
            >
              <span class="arrow">⇒</span>
              <span class="btn-text">全部</span>
            </button>
            <button 
              class="action-btn"
              @click="moveBackSelected"
              :disabled="selectedTarget.length === 0"
              title="移回选中"
            >
              <span class="arrow">←</span>
              <span class="btn-text">移回</span>
            </button>
            <button 
              class="action-btn"
              @click="moveBackAll"
              :disabled="targetList.length === 0"
              title="全部移回"
            >
              <span class="arrow">⇐</span>
              <span class="btn-text">全部</span>
            </button>
          </div>

          <!-- 右侧：目标人员 -->
          <div class="selector-panel">
            <div class="panel-header">
              <h4 class="panel-title">{{ rightTitle }}</h4>
              <span class="panel-count">{{ targetList.length }} 人</span>
            </div>
            <div class="panel-search">
              <input 
                v-model="searchTarget"
                type="text"
                placeholder="搜索人员..."
                class="search-input-small"
              />
            </div>
            <div class="panel-body">
              <div class="user-list">
                <div
                  v-for="user in filteredTarget"
                  :key="user.id"
                  class="user-item"
                  :class="{ selected: user.id && selectedTarget.includes(user.id) }"
                  @click="user.id && toggleTarget(user.id)"
                  @dblclick="user.id && moveBackToAvailable(user.id)"
                >
                  <input
                    type="checkbox"
                    :checked="!!(user.id && selectedTarget.includes(user.id))"
                    @click.stop="user.id && toggleTarget(user.id)"
                  />
                  <span class="user-name">{{ user.username }}</span>
                  <span class="user-dept" v-if="user.deptName">({{ user.deptName }})</span>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <div class="modal-footer">
        <button class="btn-primary" @click="handleConfirm" :disabled="loading">
          {{ loading ? '处理中...' : '确定' }}
        </button>
        <button class="btn-default" @click="handleCancel">取消</button>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch, nextTick } from 'vue';
import type { UserVO, ResultDomain, PageParam } from '@/types';

interface Props {
  visible?: boolean;
  mode?: 'add' | 'remove';
  title?: string;
  leftTitle?: string;
  rightTitle?: string;
  availableUsers?: UserVO[];
  initialTargetUsers?: UserVO[];
  loading?: boolean;
  // 分页加载API方法
  fetchApi?: (pageParam: PageParam, filter?: any) => Promise<ResultDomain<UserVO>>;
  // 过滤参数
  filterParams?: any;
  // 每页数量
  pageSize?: number;
  // 是否使用分页加载
  usePagination?: boolean;
}

const props = withDefaults(defineProps<Props>(), {
  visible: false,
  mode: 'add',
  title: '人员选择',
  leftTitle: '可选人员',
  rightTitle: '已选人员',
  availableUsers: () => [],
  initialTargetUsers: () => [],
  loading: false,
  pageSize: 20,
  usePagination: false
});

const emit = defineEmits<{
  'update:visible': [value: boolean];
  confirm: [users: UserVO[]];
  cancel: [];
}>();

// 数据列表
const availableList = ref<UserVO[]>([]);
const targetList = ref<UserVO[]>([]);

// 选中状态
const selectedAvailable = ref<string[]>([]);
const selectedTarget = ref<string[]>([]);

// 搜索关键词
const searchAvailable = ref('');
const searchTarget = ref('');

// 分页相关
const currentPage = ref(1);
const totalElements = ref(0);
const hasMore = ref(true);
const loadingMore = ref(false);
const availablePanelRef = ref<HTMLElement | null>(null);

// 监听props变化，初始化数据
watch(() => props.visible, (newVal) => {
  if (newVal) {
    initializeData();
  } else {
    resetData();
  }
}, { immediate: true });

// 监听搜索关键词变化
watch(searchAvailable, () => {
  if (props.usePagination && props.fetchApi) {
    resetPaginationAndLoad();
  }
});

// 初始化数据
async function initializeData() {
  if (props.usePagination && props.fetchApi) {
    // 使用分页加载
    currentPage.value = 1;
    hasMore.value = true;
    availableList.value = [];
    await loadAvailableUsers();
  } else {
    // 使用传入的数据
    availableList.value = [...props.availableUsers];
  }
  
  targetList.value = [...props.initialTargetUsers];
  selectedAvailable.value = [];
  selectedTarget.value = [];
  searchAvailable.value = '';
  searchTarget.value = '';
  
  // 绑定滚动事件
  await nextTick();
  bindScrollEvent();
}

// 重置数据
function resetData() {
  availableList.value = [];
  targetList.value = [];
  selectedAvailable.value = [];
  selectedTarget.value = [];
  searchAvailable.value = '';
  searchTarget.value = '';
  currentPage.value = 1;
  totalElements.value = 0;
  hasMore.value = true;
  loadingMore.value = false;
  
  // 解绑滚动事件
  unbindScrollEvent();
}

// 加载可选用户数据
async function loadAvailableUsers() {
  if (!props.fetchApi || loadingMore.value || !hasMore.value) return;
  
  loadingMore.value = true;
  
  try {
    const pageParam: PageParam = {
      page: currentPage.value,
      size: props.pageSize
    };
    
    // 构建过滤参数
    const filter = {
      ...props.filterParams,
      ...(searchAvailable.value ? { username: searchAvailable.value } : {})
    };
    
    const res = await props.fetchApi(pageParam, filter);
    
    if (res.success) {
      const newUsers = res.dataList || [];
      
      // 过滤掉已在右侧的用户
      const targetUserIds = targetList.value.map(u => u.id);
      const filteredUsers = newUsers.filter(u => !targetUserIds.includes(u.id));
      
      if (currentPage.value === 1) {
        availableList.value = filteredUsers;
      } else {
        availableList.value.push(...filteredUsers);
      }
      
      totalElements.value = res.pageParam?.totalElements || 0;
      const totalPages = Math.ceil(totalElements.value / props.pageSize);
      hasMore.value = currentPage.value < totalPages;
    }
  } catch (error) {
    console.error('加载用户数据失败:', error);
  } finally {
    loadingMore.value = false;
  }
}

// 重置分页并重新加载
async function resetPaginationAndLoad() {
  currentPage.value = 1;
  hasMore.value = true;
  availableList.value = [];
  await loadAvailableUsers();
}

// 绑定滚动事件
function bindScrollEvent() {
  const panelBody = document.querySelector('.panel-body.left-panel');
  if (panelBody) {
    availablePanelRef.value = panelBody as HTMLElement;
    panelBody.addEventListener('scroll', handleScroll);
  }
}

// 解绑滚动事件
function unbindScrollEvent() {
  if (availablePanelRef.value) {
    availablePanelRef.value.removeEventListener('scroll', handleScroll);
    availablePanelRef.value = null;
  }
}

// 处理滚动事件
function handleScroll(event: Event) {
  if (!props.usePagination || !props.fetchApi) return;
  
  const target = event.target as HTMLElement;
  const scrollTop = target.scrollTop;
  const scrollHeight = target.scrollHeight;
  const clientHeight = target.clientHeight;
  
  // 距离底部50px时加载更多
  if (scrollHeight - scrollTop - clientHeight < 50 && hasMore.value && !loadingMore.value) {
    currentPage.value++;
    loadAvailableUsers();
  }
}

// 过滤可选人员
const filteredAvailable = computed(() => {
  // 如果使用分页加载，搜索在API层面处理，不需要前端过滤
  if (props.usePagination) {
    return availableList.value;
  }
  
  // 前端过滤
  if (!searchAvailable.value) {
    return availableList.value;
  }
  const keyword = searchAvailable.value.toLowerCase();
  return availableList.value.filter(user => 
    user.username?.toLowerCase().includes(keyword) ||
    user.deptName?.toLowerCase().includes(keyword)
  );
});

// 过滤目标人员
const filteredTarget = computed(() => {
  if (!searchTarget.value) {
    return targetList.value;
  }
  const keyword = searchTarget.value.toLowerCase();
  return targetList.value.filter(user => 
    user.username?.toLowerCase().includes(keyword) ||
    user.deptName?.toLowerCase().includes(keyword)
  );
});

// 切换可选用户的选中状态
function toggleAvailable(userId: string) {
  const index = selectedAvailable.value.indexOf(userId);
  if (index > -1) {
    selectedAvailable.value.splice(index, 1);
  } else {
    selectedAvailable.value.push(userId);
  }
}

// 切换目标用户的选中状态
function toggleTarget(userId: string) {
  const index = selectedTarget.value.indexOf(userId);
  if (index > -1) {
    selectedTarget.value.splice(index, 1);
  } else {
    selectedTarget.value.push(userId);
  }
}

// 移动选中用户到目标区域
function moveSelectedToTarget() {
  const usersToMove = availableList.value.filter(user => 
    selectedAvailable.value.includes(user.id!)
  );
  
  targetList.value.push(...usersToMove);
  availableList.value = availableList.value.filter(user => 
    !selectedAvailable.value.includes(user.id!)
  );
  
  selectedAvailable.value = [];
}

// 移动单个用户到目标区域（双击）
function moveToTarget(userId: string) {
  const user = availableList.value.find(u => u.id === userId);
  if (user) {
    targetList.value.push(user);
    availableList.value = availableList.value.filter(u => u.id !== userId);
  }
}

// 移动所有用户到目标区域
function moveAllToTarget() {
  targetList.value.push(...availableList.value);
  availableList.value = [];
  selectedAvailable.value = [];
}

// 移回选中用户到可选区域
function moveBackSelected() {
  const usersToMoveBack = targetList.value.filter(user => 
    selectedTarget.value.includes(user.id!)
  );
  
  availableList.value.push(...usersToMoveBack);
  targetList.value = targetList.value.filter(user => 
    !selectedTarget.value.includes(user.id!)
  );
  
  selectedTarget.value = [];
}

// 移回单个用户到可选区域（双击）
function moveBackToAvailable(userId: string) {
  const user = targetList.value.find(u => u.id === userId);
  if (user) {
    availableList.value.push(user);
    targetList.value = targetList.value.filter(u => u.id !== userId);
  }
}

// 移回所有用户到可选区域
function moveBackAll() {
  availableList.value.push(...targetList.value);
  targetList.value = [];
  selectedTarget.value = [];
}

// 确认
function handleConfirm() {
  emit('confirm', targetList.value);
}

// 取消
function handleCancel() {
  emit('update:visible', false);
  emit('cancel');
}
</script>

<style lang="scss" scoped>
// 弹窗遮罩
.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2000;
}

.modal-content {
  background: #fff;
  border-radius: 8px;
  width: 90%;
  max-width: 900px;
  max-height: 80vh;
  display: flex;
  flex-direction: column;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

.modal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 20px 24px;
  border-bottom: 1px solid #f0f0f0;
}

.modal-title {
  font-size: 18px;
  font-weight: 600;
  color: #303133;
  margin: 0;
}

.modal-close {
  width: 32px;
  height: 32px;
  border: none;
  background: #f5f7fa;
  border-radius: 50%;
  cursor: pointer;
  font-size: 18px;
  color: #909399;
  transition: all 0.3s;

  &:hover {
    background: #ecf5ff;
    color: #409eff;
  }
}

.modal-body {
  flex: 1;
  overflow-y: auto;
  padding: 20px 24px;
}

.modal-footer {
  padding: 16px 24px;
  border-top: 1px solid #f0f0f0;
  display: flex;
  justify-content: flex-end;
  gap: 12px;
}

// 人员选择器样式
.user-selector {
  display: flex;
  gap: 20px;
  height: 500px;
}

.selector-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  border: 1px solid #e0e0e0;
  border-radius: 6px;
  overflow: hidden;
  background: #fafafa;
}

.panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 16px;
  background: #f5f7fa;
  border-bottom: 1px solid #e0e0e0;
}

.panel-title {
  font-size: 15px;
  font-weight: 600;
  color: #303133;
  margin: 0;
}

.panel-count {
  font-size: 13px;
  color: #909399;
  background: #fff;
  padding: 2px 10px;
  border-radius: 10px;
}

.panel-search {
  padding: 12px 16px;
  border-bottom: 1px solid #e0e0e0;
  background: #fff;
}

.search-input-small {
  width: 100%;
  padding: 8px 12px;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  font-size: 14px;
  transition: border-color 0.3s;

  &:focus {
    outline: none;
    border-color: #409eff;
  }

  &::placeholder {
    color: #c0c4cc;
  }
}

.panel-body {
  flex: 1;
  overflow-y: auto;
  padding: 8px;
  background: #fff;
}

.user-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.user-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.2s;
  user-select: none;

  &:hover {
    background: #f5f7fa;
  }

  &.selected {
    background: #ecf5ff;
    border: 1px solid #b3d8ff;
  }

  input[type="checkbox"] {
    cursor: pointer;
    width: 16px;
    height: 16px;
  }

  .user-name {
    font-size: 14px;
    color: #606266;
    font-weight: 500;
  }

  .user-dept {
    font-size: 12px;
    color: #909399;
    margin-left: auto;
  }
}

.loading-more {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 16px;
  color: #909399;
  font-size: 13px;
}

.loading-spinner-small {
  width: 16px;
  height: 16px;
  border: 2px solid #f0f0f0;
  border-top-color: #409eff;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

.no-more {
  text-align: center;
  padding: 12px;
  color: #c0c4cc;
  font-size: 12px;
}

.selector-actions {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 12px;
  padding: 0 10px;
}

.action-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 12px 16px;
  background: #fff;
  border: 1px solid #dcdfe6;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.3s;
  min-width: 80px;

  &:hover:not(:disabled) {
    background: #409eff;
    border-color: #409eff;
    color: #fff;

    .arrow {
      color: #fff;
    }

    .btn-text {
      color: #fff;
    }
  }

  &:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    background: #f5f7fa;
  }

  .arrow {
    font-size: 20px;
    font-weight: bold;
    color: #409eff;
    transition: color 0.3s;
  }

  .btn-text {
    font-size: 13px;
    color: #606266;
    transition: color 0.3s;
  }
}

.btn-primary,
.btn-default {
  padding: 10px 24px;
  border-radius: 4px;
  font-size: 14px;
  cursor: pointer;
  transition: all 0.3s;
  border: none;

  &:disabled {
    opacity: 0.6;
    cursor: not-allowed;
  }
}

.btn-primary {
  background: #409eff;
  color: #fff;

  &:hover:not(:disabled) {
    background: #66b1ff;
  }
}

.btn-default {
  background: #fff;
  color: #606266;
  border: 1px solid #dcdfe6;

  &:hover {
    color: #409eff;
    border-color: #409eff;
  }
}
</style>

