<template>
    <div v-if="visible" ref="popoverRef" class="pc-transfer-popover" :style="popoverStyle" @click.stop>
        <div class="pc-transfer-search">
            <input v-model="searchKeyword" class="pc-transfer-search-input" type="text" :placeholder="t('搜索')"
                autocomplete="off" />
            <svg class="pc-transfer-search-icon" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"
                aria-hidden="true">
                <path
                    d="M8.75 3.75a5 5 0 1 0 0 10 5 5 0 0 0 0-10Zm0-1.5a6.5 6.5 0 1 1 0 13 6.5 6.5 0 0 1 0-13Zm5.209 11.148 3.02 3.02a.75.75 0 1 1-1.06 1.061l-3.02-3.02a.75.75 0 0 1 1.06-1.06Z"
                    fill="#86909C" />
            </svg>
        </div>

        <div class="pc-transfer-tabs">
            <button class="pc-transfer-tab" :class="{ 'is-active': activeTab === 'member' }" type="button"
                @click="setActiveTab('member')">
                {{ t('转接给成员') }}
            </button>
            <button class="pc-transfer-tab" :class="{ 'is-active': activeTab === 'group' }" type="button"
                @click="setActiveTab('group')">
                {{ t('转接给分组') }}
            </button>
        </div>

        <div class="pc-transfer-list">
            <template v-if="activeTab === 'member'">
                <button v-for="contact in contacts" :key="contact.userId" class="pc-transfer-member" type="button"
                    @click="openConfirmForMember(contact)">
                    <span class="pc-transfer-member-dot" />
                    <div class="pc-transfer-member-main">
                        <div class="pc-transfer-member-name" v-html="highlightKeyword(contact.name)"></div>
                        <div class="pc-transfer-member-id" v-html="highlightKeyword(contact.userId)"></div>
                    </div>
                </button>
            </template>

            <template v-else>
                <button v-for="group in skillGroups" :key="group.skillGroupId" class="pc-transfer-group" type="button"
                    @click="openConfirmForGroup(group)">
                    <div class="pc-transfer-group-name" v-html="highlightKeyword(group.skillGroupName)"></div>
                    <div class="pc-transfer-group-meta">
                        {{ t('{count}人可转接', { count: group.freeStaffCount }) }}
                    </div>
                </button>
            </template>

            <div v-if="currentLoading && currentListLength === 0" class="pc-transfer-empty">
                {{ t('加载中...') }}
            </div>
            <div v-else-if="currentLoadError && currentListLength === 0" class="pc-transfer-empty">
                {{ currentLoadError }}
            </div>
            <div v-else-if="!currentLoading && currentListLength === 0" class="pc-transfer-empty">
                {{ activeTab === 'member' ? t('未找到匹配的客服信息') : t('未找到匹配的分组信息') }}
            </div>
        </div>
    </div>

    <t-dialog class="pc-transfer-confirm-dialog" v-model:visible="confirmDialogVisible" :close-on-overlay-click="true"
        :header="t('转接')" :body="transferConfirmText" :footer="true" width="480px" @close="handleTransferCancel">
        <template #footer>
            <div class="pc-transfer-dialog-footer">
                <button type="button" class="pc-transfer-dialog-button pc-transfer-dialog-button--cancel"
                    @click="handleTransferCancel">
                    {{ t('取消') }}
                </button>
                <button type="button" class="pc-transfer-dialog-button pc-transfer-dialog-button--confirm"
                    @click="handleTransferConfirm">
                    {{ t('确定') }}
                </button>
            </div>
        </template>
    </t-dialog>
</template>

<script setup lang="ts">
import { computed, nextTick, onBeforeUnmount, onMounted, onUnmounted, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import debounce from 'lodash/debounce';
import AIDeskCoreInstance, { StoreName } from '@tencentcloud/ai-desk-core';
import toast from '../../../../utils/toast';
import { parseUnknownError } from '../../../../utils/parseUnknownError';

interface ContactItem {
    userId: string;
    name: string;
    avatar: string;
}

interface SkillGroupItem {
    skillGroupId: string;
    skillGroupName: string;
    freeStaffCount: number;
}

type TransferTarget =
    | { type: 'member'; contact: ContactItem }
    | { type: 'group'; group: SkillGroupItem }
    | null;

type TransferTab = 'member' | 'group';

const props = defineProps<{
    visible: boolean;
    sessionId: string;
    anchor: HTMLElement | null;
}>();

const emit = defineEmits<{
    (event: 'update:visible', value: boolean): void;
    (event: 'transferred'): void;
}>();

const { t } = useI18n();

const skillGroupTypeMap = { IM: 1 as const };

const activeTab = ref<TransferTab>('member');
const searchKeyword = ref('');
const contacts = ref<ContactItem[]>([]);
const skillGroups = ref<SkillGroupItem[]>([]);
const memberLoading = ref(false);
const groupLoading = ref(false);
const memberLoadError = ref('');
const groupLoadError = ref('');
const confirmDialogVisible = ref(false);
const pendingTransferTarget = ref<TransferTarget>(null);
const popoverRef = ref<HTMLElement | null>(null);
const popoverStyle = ref<Record<string, string>>({});
const currnetUserId = ref<string>('');

onMounted(() => {
    AIDeskCoreInstance.coreStore.watch(StoreName.USERINFO, {
        userId: onCurrentUserIdUpdated,
    });
});

onUnmounted(() => {
    AIDeskCoreInstance.coreStore.unwatch(StoreName.USERINFO, {
        userId: onCurrentUserIdUpdated,
    });
});

const onCurrentUserIdUpdated = (userId: string) => {
    currnetUserId.value = userId;
};

const normalizedKeyword = computed(() => searchKeyword.value.trim());
const currentLoading = computed(() => (activeTab.value === 'member' ? memberLoading.value : groupLoading.value));
const currentLoadError = computed(() => (activeTab.value === 'member' ? memberLoadError.value : groupLoadError.value));
const currentListLength = computed(() =>
    activeTab.value === 'member' ? contacts.value.length : skillGroups.value.length,
);

const transferConfirmText = computed(() => {
    if (!pendingTransferTarget.value) return '';
    if (pendingTransferTarget.value.type === 'member') {
        const { name, userId } = pendingTransferTarget.value.contact;
        return t('确认转接给成员 {name}（{userId}）', { name, userId });
    }
    return t('确认转接给分组 {name}', {
        name: pendingTransferTarget.value.group.skillGroupName,
    });
});

const loadContacts = async () => {
    memberLoading.value = true;
    memberLoadError.value = '';
    try {
        const result = await AIDeskCoreInstance.sessionService.getStaffList({
            pageNum: 0,
            pageSize: 2000,
            status: [100, 700],
            isNeedStatus: true,
            skillGroupType: skillGroupTypeMap.IM,
            ...(normalizedKeyword.value && { fuzzingKeyWord: normalizedKeyword.value }),
        });
        contacts.value = result.staffList
            .filter((staff) => staff.userId !== currnetUserId.value)
            .map((staff) => ({
                userId: staff.userId,
                name: staff.nickName || staff.staffName || staff.userId,
                avatar: staff.avatar || '',
            }));
    } catch (error) {
        console.error(error);
        contacts.value = [];
        memberLoadError.value = t('获取客服列表失败');
    } finally {
        memberLoading.value = false;
    }
};

const loadSkillGroups = async () => {
    groupLoading.value = true;
    groupLoadError.value = '';
    try {
        const result = await AIDeskCoreInstance.sessionService.getSkillGroupList({
            skillGroupType: skillGroupTypeMap.IM,
            ...(normalizedKeyword.value && { fuzzingKeyWord: normalizedKeyword.value }),
        });
        skillGroups.value = (result.skillGroupList ?? []).map((item) => ({
            skillGroupId: item.skillGroupId,
            skillGroupName: item.skillGroupName,
            freeStaffCount: item.freeCntExceptReqMember ?? item.freeStaffCount ?? 0,
        }));
    } catch (error) {
        console.error(error);
        skillGroups.value = [];
        groupLoadError.value = t('获取分组列表失败');
    } finally {
        groupLoading.value = false;
    }
};

const fetchTransferList = debounce(() => {
    if (activeTab.value === 'member') {
        loadContacts();
    } else {
        loadSkillGroups();
    }
}, 300);

const escapeHtml = (value: string) =>
    value
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#39;');

const escapeRegExp = (value: string) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

const highlightKeyword = (value: string) => {
    const safe = escapeHtml(value ?? '');
    if (!normalizedKeyword.value) return safe;
    const pattern = new RegExp(`(${escapeRegExp(normalizedKeyword.value)})`, 'ig');
    return safe.replace(pattern, '<span class="pc-transfer-keyword">$1</span>');
};

const setActiveTab = (tab: TransferTab) => {
    activeTab.value = tab;
};

const openConfirmForMember = (contact: ContactItem) => {
    pendingTransferTarget.value = { type: 'member', contact };
    confirmDialogVisible.value = true;
};

const openConfirmForGroup = (group: SkillGroupItem) => {
    pendingTransferTarget.value = { type: 'group', group };
    confirmDialogVisible.value = true;
};

const closePopover = () => {
    emit('update:visible', false);
};

const handleTransferCancel = () => {
    confirmDialogVisible.value = false;
    pendingTransferTarget.value = null;
};

const handleTransferConfirm = async () => {
    const target = pendingTransferTarget.value;
    if (!target) {
        confirmDialogVisible.value = false;
        return;
    }
    confirmDialogVisible.value = false;
    try {
        if (target.type === 'member') {
            await AIDeskCoreInstance.sessionService.transferSession({
                sessionId: props.sessionId,
                userId: target.contact.userId,
            });
        } else {
            await AIDeskCoreInstance.sessionService.transferSession({
                sessionId: props.sessionId,
                skillGroupId: target.group.skillGroupId,
            });
        }
        emit('transferred');
        closePopover();
    } catch (error) {
        console.error(error);
        toast.error(parseUnknownError(error))
    } finally {
        pendingTransferTarget.value = null;
    }
};

const updatePopoverPosition = () => {
    if (!props.anchor) return;
    const rect = props.anchor.getBoundingClientRect();
    // 弹窗使用固定宽度，保证 tab、列表等内容有足够展示空间
    const popoverWidth = 320;
    // 让弹窗中心对齐按钮中心
    const anchorCenter = rect.left + rect.width / 2;
    let left = anchorCenter - popoverWidth / 2;
    if (left + popoverWidth > window.innerWidth - 8) {
        left = window.innerWidth - popoverWidth - 8;
    }
    if (left < 8) left = 8;
    const top = rect.bottom + 8;
    popoverStyle.value = {
        position: 'fixed',
        top: `${top}px`,
        left: `${left}px`,
        width: `${popoverWidth}px`,
        zIndex: '2000',
    };
};

const handleDocumentClick = (event: MouseEvent) => {
    if (!props.visible) return;
    const target = event.target as Node | null;
    if (popoverRef.value && target && popoverRef.value.contains(target)) return;
    if (props.anchor && target && props.anchor.contains(target)) return;
    closePopover();
};

const handleWindowResize = () => {
    updatePopoverPosition();
};

watch(
    () => props.visible,
    async (val) => {
        if (val) {
            searchKeyword.value = '';
            activeTab.value = 'member';
            await nextTick();
            // 使用 rAF 等浏览器完成一次布局，避免首次打开时 anchor 的 rect 尚未稳定
            updatePopoverPosition();
            requestAnimationFrame(() => {
                updatePopoverPosition();
            });
            fetchTransferList();
            document.addEventListener('mousedown', handleDocumentClick);
            window.addEventListener('resize', handleWindowResize);
            window.addEventListener('scroll', handleWindowResize, true);
        } else {
            document.removeEventListener('mousedown', handleDocumentClick);
            window.removeEventListener('resize', handleWindowResize);
            window.removeEventListener('scroll', handleWindowResize, true);
        }
    },
);

// anchor 引用变化时（例如 headerActions 因 session 状态变化重新渲染导致按钮重建），同步刷新位置
watch(
    () => props.anchor,
    () => {
        if (props.visible) {
            nextTick(() => updatePopoverPosition());
        }
    },
);

watch([searchKeyword, activeTab], () => {
    if (!props.visible) return;
    fetchTransferList();
});

onBeforeUnmount(() => {
    fetchTransferList.cancel();
    document.removeEventListener('mousedown', handleDocumentClick);
    window.removeEventListener('resize', handleWindowResize);
    window.removeEventListener('scroll', handleWindowResize, true);
});
</script>

<style scoped>
.pc-transfer-popover {
    background: #fff;
    border-radius: 8px;
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.12);
    padding: 12px 0 8px;
    display: flex;
    flex-direction: column;
    max-height: 460px;
    overflow: hidden;
}

.pc-transfer-search {
    position: relative;
    margin: 0 16px 8px;
}

.pc-transfer-search-input {
    width: 100%;
    height: 32px;
    padding: 0 28px 0 0;
    border: none;
    border-bottom: 1px solid #165dff;
    outline: none;
    font-size: 14px;
    color: #1d2129;
    background: transparent;
}

.pc-transfer-search-input::placeholder {
    color: #a5a9b0;
}

.pc-transfer-search-icon {
    position: absolute;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    width: 18px;
    height: 18px;
    pointer-events: none;
}

.pc-transfer-tabs {
    display: flex;
    align-items: center;
    padding: 4px 16px 0;
    border-bottom: 1px solid #f0f0f0;
    margin-bottom: 4px;
}

.pc-transfer-tab {
    position: relative;
    flex: 1;
    height: 36px;
    padding: 0;
    border: none;
    background: transparent;
    font-size: 14px;
    color: #86909c;
    cursor: pointer;
    text-align: center;
}

.pc-transfer-tab.is-active {
    color: #1d2129;
    font-weight: 600;
}

.pc-transfer-tab.is-active::after {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    bottom: -1px;
    height: 2px;
    background: #165dff;
    border-radius: 1px;
}

.pc-transfer-list {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 4px 0;
}

.pc-transfer-member {
    width: 100%;
    padding: 10px 16px;
    border: none;
    background: transparent;
    display: flex;
    align-items: flex-start;
    gap: 8px;
    text-align: left;
    cursor: pointer;
}

.pc-transfer-member:hover,
.pc-transfer-group:hover {
    background: #f5f7fa;
}

.pc-transfer-member-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: #14ca64;
    margin-top: 8px;
    flex-shrink: 0;
}

.pc-transfer-member-main {
    min-width: 0;
    flex: 1;
}

.pc-transfer-member-name {
    font-size: 14px;
    line-height: 22px;
    color: #1d2129;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pc-transfer-member-id {
    margin-top: 2px;
    font-size: 12px;
    line-height: 18px;
    color: #a5a9b0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pc-transfer-group {
    width: 100%;
    padding: 10px 16px;
    border: none;
    background: transparent;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    text-align: left;
    cursor: pointer;
    box-sizing: border-box;
}

.pc-transfer-group-name {
    flex: 1;
    min-width: 0;
    font-size: 14px;
    line-height: 22px;
    color: #1d2129;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.pc-transfer-group-meta {
    flex-shrink: 0;
    font-size: 12px;
    line-height: 18px;
    color: #a5a9b0;
}

.pc-transfer-empty {
    padding: 20px 0;
    text-align: center;
    font-size: 13px;
    color: #a5a9b0;
}

:deep(.pc-transfer-keyword) {
    color: #165dff;
}

.pc-transfer-dialog-footer {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 16px;
    padding: 8px 0 4px;
}

.pc-transfer-dialog-button {
    min-width: 120px;
    height: 40px;
    padding: 0 32px;
    border-radius: 999px;
    font-size: 14px;
    line-height: 20px;
    cursor: pointer;
    border: 1px solid transparent;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    box-sizing: border-box;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.pc-transfer-dialog-button--cancel {
    background: #fff;
    color: #1d2129;
    border-color: #d9d9d9;
}

.pc-transfer-dialog-button--cancel:hover {
    border-color: #316EF5;
    color: #316EF5;
}

.pc-transfer-dialog-button--confirm {
    background: #316EF5;
    color: #fff;
    border-color: #316EF5;
}

.pc-transfer-dialog-button--confirm:hover {
    background: #2A5FDB;
    border-color: #2A5FDB;
}
</style>

<style>
/* 非 scoped，用于覆盖 TDesign Dialog teleport 到 body 外的样式 */
.pc-transfer-confirm-dialog .t-dialog__footer {
    text-align: center !important;
    padding: 0 !important;
}

.pc-transfer-confirm-dialog .t-dialog__footer .t-button+.t-button {
    margin-left: 0 !important;
}
</style>
