<template>
    <div class="session-list-container">
        <div v-if="isOfflineState" class="offline-state">
            <img :src="offlineIcon" class="offline-state-icon" alt="offline status" />
            <template v-if="isSeatOffline">
                <div class="offline-state-title">{{ t('您当前处于下线状态') }}</div>
                <div class="offline-state-desc">{{ t('请切换为在线状态，以查看并回复访客消息') }}</div>
            </template>
            <template v-else>
                <div class="offline-state-title">{{ t('IM 网络状态断开') }}</div>
            </template>
        </div>
        <div v-else-if="filteredSessions.length > 0" class="session-list-content"
            @scroll.passive="handleSessionListScroll">
            <template v-if="isMobile">
                <MobileSessionItem v-for="session in filteredSessions" :key="session.id" :session="session"
                    :is-swipe-open="openedSwipeId === session.id" @click="handleSessionClick(session)"
                    @swipe-open="handleSwipeOpen(session.id)" @swipe-close="handleSwipeClose(session.id)"
                    @mark-unread="handleMarkUnread(session.id)" @toggle-mark="handleToggleMark(session.id)"
                    @delete="handleDelete(session.id)" @accept="handleAcceptSession(session.id)" />
            </template>
            <template v-else>
                <PCSessionItem v-for="session in filteredSessions" :key="session.id" :session="session"
                    :current-session-id="currentSessionId" @click="handleSessionClick(session)"
                    @accept="handleAcceptSession(session.id)" @mark-unread="handleMarkUnread(session.id)"
                    @toggle-mark="handleToggleMark(session.id)" @delete="handleDelete(session.id)" />
            </template>
        </div>
        <div v-else class="empty-state">
            {{ t('暂无会话') }}
        </div>
    </div>
</template>

<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
import { useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
import PCSessionItem from './PCSessionItem.vue';
import MobileSessionItem from './MobileSessionItem.vue';
import offlineIcon from './offline.svg';
import AIDeskCoreInstance, { SESSION_TYPE, StoreName, type ISessionModel } from '@tencentcloud/ai-desk-core';
import { isMobile } from '../../utils/env';
import { formateMessageAbstract, getSessionShowSource, getSessionShowTime } from '../../utils/index.ts';

export type SessionSwipeAction = 'mark-unread' | 'toggle-mark' | 'delete';

export interface Session {
    id: string;
    type: SESSION_TYPE.IM | SESSION_TYPE.ROBOT | SESSION_TYPE.IM_QUEUE | SESSION_TYPE.IM_OTHER_INPROGRESS;
    name: string;
    lastMsg: string;
    unread?: number;
    time?: string;
    avatar?: string;
    source?: string;
    marked?: boolean;
    sessionState?: string;
    isInnerSession?: boolean;
    channelName?: string;
    timeout?: number;
    overlayText?: string;
    statusHint?: string;
    IMReplyTimeOut: number;
    seatStatus?: string;
    restReason?: string;
    swipeActions: SessionSwipeAction[];
}

const SESSION_STATUS_HINT_KEY = '3 秒后将自动移出列表';
const SESSION_LIST_LOAD_MORE_THRESHOLD = 24;

type SessionTabType = SESSION_TYPE.IM | SESSION_TYPE.IM_OTHER_INPROGRESS | SESSION_TYPE.IM_QUEUE | SESSION_TYPE.ROBOT;
type SessionTabValue = {
    type: SessionTabType;
    meta?: string;
};

type SessionSourceItem =
    | ISessionModel<SESSION_TYPE.IM>
    | ISessionModel<SESSION_TYPE.ROBOT>
    | ISessionModel<SESSION_TYPE.IM_QUEUE>
    | ISessionModel<SESSION_TYPE.IM_OTHER_INPROGRESS>;

type ConnectionState = 'disconnected' | 'connected' | 'connecting' | 'reconnecting';

type NetStatus = 'reconnecting' | 'connected';

const props = defineProps<{
    currentTab: SessionTabValue;
    // 仅 PC 端使用：为 true 时 outer tab 将内部会话也包含在“我的”列表中
    mergeInner?: boolean;
    // 仅 PC 端使用：为 true 时会话列表中隐藏 ringing 状态的会话（由悬浮框展示）
    hideRinging?: boolean;
}>();

const router = useRouter();
const { t, locale } = useI18n();
const openedSwipeId = ref<string | null>(null);
const IMSessionList = ref<ISessionModel<SESSION_TYPE.IM>[]>([]);
const IMRobotSessionList = ref<ISessionModel<SESSION_TYPE.ROBOT>[]>([]);
const IMQueueSessionList = ref<ISessionModel<SESSION_TYPE.IM_QUEUE>[]>([]);
const IMOtherInprogressSessionList = ref<ISessionModel<SESSION_TYPE.IM_OTHER_INPROGRESS>[]>([]);
const currnetUserId = ref<string>('');
const connectionState = ref<ConnectionState>('disconnected');
const IMNetStatus = ref<NetStatus>('connected');
const filteredSessions = ref<Session[]>([]);
const currentSessionId = ref<string>('');
const minuteTick = ref(Date.now());
const isLoadingMoreOtherSeatInprogressSessions = ref(false);
let minuteRefreshTimer: ReturnType<typeof window.setInterval> | null = null;

onMounted(() => {
    AIDeskCoreInstance.coreStore.watch(StoreName.SESSION, {
        IMSessionList: onIMSessionListUpdated,
        IMRobotSessionList: onIMRobotSessionListUpdated,
        IMQueueSessionList: onIMQueueSessionListUpdated,
        IMOtherInprogressSessionList: onIMOtherInprogressSessionListUpdated,
        currentSession: onCurrentSessionUpdated,
    });
    AIDeskCoreInstance.coreStore.watch(StoreName.USERINFO, {
        userId: onCurrentUserIdUpdated,
        connectionState: onConnectionStateUpdated,
        IMNetStatus: onIMNetStatusUpdated,
    });
    minuteRefreshTimer = window.setInterval(() => {
        minuteTick.value = Date.now();
    }, 60000);
});

onUnmounted(() => {
    AIDeskCoreInstance.coreStore.unwatch(StoreName.SESSION, {
        IMSessionList: onIMSessionListUpdated,
        IMRobotSessionList: onIMRobotSessionListUpdated,
        IMQueueSessionList: onIMQueueSessionListUpdated,
        IMOtherInprogressSessionList: onIMOtherInprogressSessionListUpdated,
        currentSession: onCurrentSessionUpdated,
    });
    AIDeskCoreInstance.coreStore.unwatch(StoreName.USERINFO, {
        userId: onCurrentUserIdUpdated,
        connectionState: onConnectionStateUpdated,
        IMNetStatus: onIMNetStatusUpdated,
    });
    if (minuteRefreshTimer !== null) {
        window.clearInterval(minuteRefreshTimer);
        minuteRefreshTimer = null;
    }
});

const onIMSessionListUpdated = (list: ISessionModel<SESSION_TYPE.IM>[]) => {
    IMSessionList.value = list ?? [];
};

const onIMRobotSessionListUpdated = (list: ISessionModel<SESSION_TYPE.ROBOT>[]) => {
    IMRobotSessionList.value = list ?? [];
};

const onIMQueueSessionListUpdated = (list: ISessionModel<SESSION_TYPE.IM_QUEUE>[]) => {
    IMQueueSessionList.value = list ?? [];
};

const onIMOtherInprogressSessionListUpdated = (list: ISessionModel<SESSION_TYPE.IM_OTHER_INPROGRESS>[]) => {
    IMOtherInprogressSessionList.value = list ?? [];
};

const onCurrentSessionUpdated = (session: { sessionId: string; sessionType: SESSION_TYPE | ''; sessionData: unknown }) => {
    currentSessionId.value = session?.sessionId || '';
};

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

const onConnectionStateUpdated = (state: ConnectionState) => {
    connectionState.value = state;
};

const onIMNetStatusUpdated = (status: NetStatus) => {
    IMNetStatus.value = status;
};

const getSessionSourceList = (sessionTab: SessionTabValue): SessionSourceItem[] => {
    switch (sessionTab.type) {
        case SESSION_TYPE.IM:
            if (sessionTab.meta === 'outer') {
                return IMSessionList.value.filter((item) => {
                    const isInProgressState = (
                        item.sessionData.sessionState === "ringing" ||
                        item.sessionData.sessionState === "inProgress" ||
                        item.sessionData.sessionState === "seatJoining"
                    );
                    if (props.hideRinging && item.sessionData.sessionState === 'ringing') {
                        return false;
                    }
                    if (props.mergeInner) {
                        return isInProgressState;
                    }
                    return !item.sessionData.isInnerSession && isInProgressState;
                })
            }
            if (sessionTab.meta === 'inner') {
                return IMSessionList.value.filter((item) => {
                    return item.sessionData.isInnerSession;
                })
            }
            if (sessionTab.meta === 'unread') {
                return IMSessionList.value.filter((item) => {
                    return item.sessionData.unreadCount > 0;
                })
            }
            if (sessionTab.meta === 'star') {
                return IMSessionList.value.filter((item) => {
                    return item.sessionData.starStatus === 1;
                })
            }
            if (sessionTab.meta === 'ended') {
                return IMSessionList.value.filter((item) => {
                    return item.sessionData.sessionState === "finished";
                })
            }
            return []
        case SESSION_TYPE.IM_QUEUE:
            return IMQueueSessionList.value
        case SESSION_TYPE.IM_OTHER_INPROGRESS:
            return IMOtherInprogressSessionList.value;
        case SESSION_TYPE.ROBOT:
            if (sessionTab.meta === 'wait-human') {
                return IMRobotSessionList.value.filter((item) => item.sessionData.transToAgentTimes !== 0);
            }
            if (sessionTab.meta === 'robot') {
                return IMRobotSessionList.value.filter((item) => item.sessionData.transToAgentTimes === 0);
            }
            return []
        default:
            return [];
    }
};

const canMarkSessionUnread = (session: SessionSourceItem) => {
    return session.sessionData.type === SESSION_TYPE.IM && session.sessionData.unreadCount === 0;
};

const getSessionSwipeActions = (sessionTab: SessionTabValue, session: SessionSourceItem): SessionSwipeAction[] => {
    if (sessionTab.type !== SESSION_TYPE.IM || session.sessionData.type !== SESSION_TYPE.IM) {
        return [];
    }

    if (sessionTab.meta === 'outer') {
        if (session.sessionData.sessionState !== 'inProgress') {
            return [];
        }

        const isInnerSession = Boolean(session.sessionData.isInnerSession);

        if (isInnerSession) {
            return canMarkSessionUnread(session)
                ? ['mark-unread', 'delete']
                : ['delete'];
        }

        return canMarkSessionUnread(session)
            ? ['mark-unread', 'toggle-mark']
            : ['toggle-mark'];
    }

    if (sessionTab.meta === 'inner') {
        return canMarkSessionUnread(session)
            ? ['mark-unread', 'delete']
            : ['delete'];
    }

    return [];
};

const getSessionOverlayText = (session: SessionSourceItem) => {
    if (session.sessionData.type === SESSION_TYPE.ROBOT) {
        if (session.sessionData.transferStatus === 'my') {
            return t('会话已转至“我的”');
        }
        if (session.sessionData.transferStatus === 'other') {
            return t('会话已介入');
        }
        if (session.sessionData.transferStatus === 'allocation') {
            return t('会话已分配');
        }
        return '';
    }

    if (session.sessionData.type === SESSION_TYPE.IM_QUEUE) {
        return session.sessionData.currentState !== 'Queueing'
            ? t('会话已分配')
            : '';
    }

    if (session.sessionData.type === SESSION_TYPE.IM_OTHER_INPROGRESS) {
        if (session.sessionData.memberOutType === 1) {
            return t('会话已转接');
        }
        if (session.sessionData.memberOutType === 2) {
            return t('会话已结束');
        }
    }

    return '';
};

const getSessionName = (session: SessionSourceItem) => {
    if (session.sessionData.type === SESSION_TYPE.IM_OTHER_INPROGRESS) {
        const currentStaffName = session.sessionData.currentStaffNickName || session.sessionData.currentStaff || '';
        const targetUserName = session.sessionData.nickname || session.sessionData.userId || '';

        return `${currentStaffName}-${targetUserName}` || session.sessionData.userId;
    }

    return session.sessionData.nickname || session.sessionData.userId;
};

const mapSessionItem = (session: SessionSourceItem, swipeActions: SessionSwipeAction[]): Session => {
    const isInnerSession = session.sessionData.type === SESSION_TYPE.IM && Boolean(session.sessionData.isInnerSession);
    const isRingingSession = session.sessionData.type === SESSION_TYPE.IM && session.sessionData.sessionState === 'ringing';
    const overlayText = getSessionOverlayText(session);

    return {
        id: session.sessionId,
        type: session.sessionData.type,
        name: getSessionName(session),
        lastMsg: isRingingSession
            ? t('新分配会话，倒计时结束前介入')
            : session.sessionData.lastMessage
                ? formateMessageAbstract(session.sessionData.lastMessage, currnetUserId.value)
                : '',
        unread: session.sessionData.type === SESSION_TYPE.IM && session.sessionData.sessionState === 'inProgress' ? session.sessionData.unreadCount : 0,
        time: getSessionShowTime((session.sessionData.lastMessage?.time || session.sessionData.lastMessage?.lastTime) || session.sessionData.timestamp),
        avatar: session.sessionData.avatar,
        source: isInnerSession ? undefined : getSessionShowSource(session.sessionData.peerSource, session.sessionData.clientData),
        marked: session.sessionData.type === SESSION_TYPE.IM ? Boolean(session.sessionData.starStatus) : false,
        sessionState: session.sessionData.type === SESSION_TYPE.IM ? session.sessionData.sessionState : undefined,
        isInnerSession,
        channelName: session.sessionData.channelName,
        timeout: session.sessionData.type === SESSION_TYPE.IM ? session.sessionData.timeout : undefined,
        overlayText: overlayText || undefined,
        statusHint: overlayText ? t(SESSION_STATUS_HINT_KEY) : undefined,
        IMReplyTimeOut: session.sessionData.type === SESSION_TYPE.IM ? session.sessionData.IMReplyTimeOut || 0 : 0,
        seatStatus: session.sessionData.type === SESSION_TYPE.IM_OTHER_INPROGRESS ? session.sessionData.seatStatus : undefined,
        restReason: session.sessionData.type === SESSION_TYPE.IM_OTHER_INPROGRESS ? session.sessionData.restReason : undefined,
        swipeActions,
    };
};

const getSessionSortTimestamp = (session: SessionSourceItem) => {
    return Number(
        (session.sessionData.lastMessage?.time || session.sessionData.lastMessage?.lastTime) ||
        session.sessionData.timestamp ||
        0,
    );
};

const buildSessions = (sessionTab: SessionTabValue) => {
    return getSessionSourceList(sessionTab)
        .slice()
        .sort((a, b) => getSessionSortTimestamp(b) - getSessionSortTimestamp(a))
        .map((session) => mapSessionItem(session, getSessionSwipeActions(sessionTab, session)));
};

watch(() => props.currentTab, () => {
    openedSwipeId.value = null;
});

watch(
    [
        () => props.currentTab,
        IMSessionList,
        IMRobotSessionList,
        IMQueueSessionList,
        IMOtherInprogressSessionList,
        currnetUserId,
        minuteTick,
        locale,
    ],
    () => {
        filteredSessions.value = buildSessions(props.currentTab);
    },
    { immediate: true },
);

const isSeatOffline = computed(() => connectionState.value !== 'connected');
const isIMDisconnected = computed(() => IMNetStatus.value === 'reconnecting');
const isOfflineState = computed(() => isSeatOffline.value || isIMDisconnected.value);
const isAllSessionsTab = computed(() => props.currentTab.type === SESSION_TYPE.IM_OTHER_INPROGRESS);

// PC 端：当离线状态从 false 变为 true 时，清空当前会话的选择状态
watch(isOfflineState, (newVal, oldVal) => {
    if (!isMobile && newVal && !oldVal) {
        AIDeskCoreInstance.sessionService.switchSession({ sessionId: '', sessionType: '' });
    }
});

const handleSessionListScroll = async (event: Event) => {
    if (!isAllSessionsTab.value || isLoadingMoreOtherSeatInprogressSessions.value) {
        return;
    }

    const container = event.currentTarget as HTMLDivElement | null;

    if (!container) {
        return;
    }

    const reachedBottom = container.scrollTop + container.clientHeight + SESSION_LIST_LOAD_MORE_THRESHOLD >= container.scrollHeight;

    if (!reachedBottom) {
        return;
    }

    isLoadingMoreOtherSeatInprogressSessions.value = true;

    try {
        await AIDeskCoreInstance.sessionService.getMoreOtherSeatInprogressChatSessions();
    } finally {
        isLoadingMoreOtherSeatInprogressSessions.value = false;
    }
};

const handleSwipeOpen = (sessionId: string) => {
    openedSwipeId.value = sessionId;
};

const handleSwipeClose = (sessionId: string) => {
    if (openedSwipeId.value === sessionId) {
        openedSwipeId.value = null;
    }
};

const handleMarkUnread = (sessionId: string) => {
    const session = filteredSessions.value.find((item) => item.id === sessionId);

    if (!session || (session.unread ?? 0) > 0) {
        openedSwipeId.value = null;
        return;
    }

    AIDeskCoreInstance.sessionService.markSessionUnread(sessionId);
    openedSwipeId.value = null;
};

const handleToggleMark = (sessionId: string) => {
    AIDeskCoreInstance.sessionService.markSession(sessionId);
    openedSwipeId.value = null;
};

const handleDelete = (sessionId: string) => {
    AIDeskCoreInstance.sessionService.hideInnerSessions([sessionId]);
    if (currentSessionId.value === sessionId) {
        AIDeskCoreInstance.sessionService.switchSession({ sessionId: '', sessionType: '' });
    }
    openedSwipeId.value = null;
};

const handleAcceptSession = (sessionId: string) => {
    AIDeskCoreInstance.sessionService.acceptSession(sessionId);
    openedSwipeId.value = null;
};

const handleSessionClick = async (session: Session) => {
    if (session.type === SESSION_TYPE.IM) {
        if (session.isInnerSession) {
            AIDeskCoreInstance.chatService.setMessageRead(session.id);
        } else if (session.sessionState === 'ringing' || session.sessionState === 'seatJoining') {
            return;
        } else if (session.sessionState === 'inProgress') {
            AIDeskCoreInstance.chatService.setMessageRead(session.id);
        }
    }
    openedSwipeId.value = null;
    AIDeskCoreInstance.sessionService.switchSession({ sessionId: session.id, sessionType: session.type })
    if (isMobile) {
        router.push({
            path: `/mobileDesk/chat/${session.id}`,
            query: {
                sessionType: session.type,
                sessionName: session.name,
            },
        });
    }

};
</script>

<style scoped>
.session-list-container {
    flex: 1;
    min-height: 0;
    overflow: hidden;
}

.session-list-content {
    height: 100%;
    overflow-y: auto;
    background: #fff;
    scrollbar-width: thin;
    scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
}

.session-list-content::-webkit-scrollbar {
    width: 4px;
    height: 4px;
    background: transparent;
}

.session-list-content::-webkit-scrollbar-track {
    background: transparent;
    border: none;
    box-shadow: none;
}

.session-list-content::-webkit-scrollbar-thumb {
    background-color: rgba(0, 0, 0, 0.2);
    border-radius: 4px;
}

.session-list-content::-webkit-scrollbar-thumb:hover {
    background-color: rgba(0, 0, 0, 0.35);
}

.session-list-content::-webkit-scrollbar-corner {
    background: transparent;
}

.offline-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100%;
    padding: 0 32px;
    text-align: center;
    background: #fff;
}

.offline-state-icon {
    width: 200px;
    max-width: 100%;
    height: auto;
}

.offline-state-title {
    margin-top: 24px;
    color: #A5A9B0;
    font-size: 16px;
    line-height: 24px;
    font-weight: 500;
}

.offline-state-desc {
    margin-top: 8px;
    color: #A5A9B0;
    font-size: 14px;
    line-height: 22px;
}

.empty-state {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    color: #999;
    font-size: 14px;
}
</style>
