<template>
    <div class="pc-session-item" :class="{ active: isActive, 'is-ringing': isRinging, 'is-non-clickable': isDisabled }"
        @click="handleClick" @contextmenu="handleContextMenu">
        <div class="avatar-wrapper">
            <div class="avatar-shell" :class="{ 'is-ringing': isRinging }" :style="ringingAvatarStyle">
                <div class="avatar" :class="{ 'is-ringing': isRinging }">
                    <img class="avatar-image" :src="session.avatar || defaultAvatar" alt="" />
                </div>
            </div>
            <span v-if="session.unread" class="avatar-badge" :class="{ 'is-single': session.unread < 10 }">{{
                session.unread > 99 ? '99+' : session.unread }}</span>
        </div>
        <div class="info" :class="{ 'is-ringing': isRinging }">
            <div class="top-row">
                <div class="name-row">
                    <SessionSeatStatus v-if="session.type === 'im_other_inprogress' && session.seatStatus"
                        :seat-status="session.seatStatus" :rest-reason="session.restReason" />
                    <span class="name">{{ session.name }}</span>
                </div>
                <div class="meta-info" :class="{ 'is-ringing': isRinging, 'status-meta': showSessionStatus }">
                    <button v-if="isRinging" class="accept-btn" type="button" @click.stop="handleAccept">
                        {{ t('介入（{seconds}）', { seconds: displayTimeout }) }}
                    </button>
                    <template v-else-if="showSessionStatus">
                        <img class="status-icon" :src="correctIcon" alt="" />
                        <span class="status-text">{{ session.overlayText }}</span>
                    </template>
                    <template v-else>
                        <span class="source" v-if="session.source">{{ session.source }}</span>
                        <SessionReplyTimeout v-if="session.IMReplyTimeOut > 0"
                            :initial-seconds="session.IMReplyTimeOut" />
                        <span class="time" v-else-if="session.time">{{ session.time }}</span>
                    </template>
                </div>
            </div>
            <div v-if="middleTagText || session.marked" class="middle-row">
                <span v-if="middleTagText" class="middle-tag">{{ middleTagText }}</span>
                <img v-if="session.marked" class="marked-icon" :src="sessionMarkedIcon" alt="marked" />
            </div>
            <div class="bottom-row">
                <span class="msg" :class="{ 'msg-placeholder': !session.lastMsg }">{{ session.lastMsg || t('占位')
                }}</span>
                <span v-if="showSessionStatus && session.statusHint" class="status-hint">{{ session.statusHint }}</span>
            </div>
        </div>
        <div v-if="showSessionStatus" class="session-overlay">
            <img class="session-overlay-icon" :src="transferToMyIcon" alt="" />
            <span class="session-overlay-text">{{ session.overlayText }}</span>
        </div>

        <Teleport to="body">
            <div v-if="contextMenuVisible" ref="contextMenuRef" class="pc-session-context-menu"
                :style="{ top: contextMenuPosition.top + 'px', left: contextMenuPosition.left + 'px' }" @mousedown.stop
                @click.stop @contextmenu.prevent>
                <button v-for="action in contextMenuActions" :key="action.key" type="button"
                    class="pc-session-context-menu-item" :class="{ danger: action.key === 'delete' }" @mousedown.stop
                    @click.stop="handleContextMenuAction(action.key)">
                    {{ action.label }}
                </button>
            </div>
        </Teleport>
    </div>
</template>

<script setup lang="ts">
import { computed, onUnmounted, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import type { Session } from './index.vue';
import defaultAvatar from '../../assets/icons/defaultAvatar.svg';
import correctIcon from '../../assets/icons/correct.svg';
import transferToMyIcon from './transferToMy.svg';
import sessionMarkedIcon from './sessionMarked.svg';
import SessionReplyTimeout from './SessionReplyTimeout.vue';
import SessionSeatStatus from './SessionSeatStatus.vue';

const props = defineProps<{
    session: Session;
    currentSessionId?: string;
}>();

const emit = defineEmits<{
    (e: 'click'): void;
    (e: 'accept'): void;
    (e: 'mark-unread'): void;
    (e: 'toggle-mark'): void;
    (e: 'delete'): void;
}>();

const { t } = useI18n();

const RINGING_TIMER_INTERVAL = 100;

const isActive = computed(() => Boolean(props.currentSessionId) && props.currentSessionId === props.session.id);
const now = ref(Date.now());
const countdownStartAt = ref(Date.now());
const countdownDuration = ref(0);
let ringingTimer: number | undefined;

const isDisabled = computed(() => Boolean(props.session.overlayText));
const isRinging = computed(() => props.session.sessionState === 'ringing');
const showSessionStatus = computed(() => Boolean(props.session.overlayText));
const middleTagText = computed(() => {
    if (props.session.isInnerSession) {
        return t('内部会话');
    }
    if (props.session.channelName) {
        return `@${props.session.channelName}`;
    }
    return '';
});
const timeoutValue = computed(() => {
    const nextTimeout = Number(props.session.timeout ?? 0);
    return Number.isFinite(nextTimeout) ? Math.max(nextTimeout, 0) : 0;
});
const remainingTimeout = computed(() => {
    if (!isRinging.value) {
        return timeoutValue.value;
    }

    if (countdownDuration.value <= 0) {
        return 0;
    }

    const elapsedSeconds = Math.max((now.value - countdownStartAt.value) / 1000, 0);
    return Math.max(countdownDuration.value - elapsedSeconds, 0);
});
const displayTimeout = computed(() => Math.max(0, Math.ceil(remainingTimeout.value)));
const ringProgress = computed(() => {
    if (countdownDuration.value <= 0) {
        return 0;
    }

    return Math.min(1, Math.max(remainingTimeout.value / countdownDuration.value, 0));
});
const ringingAvatarStyle = computed(() => {
    if (!isRinging.value) {
        return undefined;
    }

    const elapsedAngle = (1 - ringProgress.value) * 360;
    return {
        background: `conic-gradient(from 0deg, #E4F7EE 0deg ${elapsedAngle}deg, #0ABF77 ${elapsedAngle}deg 360deg)`,
    };
});

const stopRingingTimer = () => {
    if (ringingTimer !== undefined) {
        window.clearInterval(ringingTimer);
        ringingTimer = undefined;
    }
};

const startRingingTimer = () => {
    stopRingingTimer();

    const nextTimeout = timeoutValue.value;
    countdownDuration.value = nextTimeout;
    countdownStartAt.value = Date.now();
    now.value = countdownStartAt.value;

    if (!isRinging.value || nextTimeout <= 0) {
        return;
    }

    ringingTimer = window.setInterval(() => {
        now.value = Date.now();
        if (remainingTimeout.value <= 0) {
            stopRingingTimer();
        }
    }, RINGING_TIMER_INTERVAL);
};

watch(
    [isRinging, () => props.session.timeout],
    () => {
        startRingingTimer();
    },
    { immediate: true },
);

onUnmounted(() => {
    stopRingingTimer();
});

const handleClick = () => {
    if (isDisabled.value) {
        return;
    }

    emit('click');
};

const handleAccept = () => {
    emit('accept');
};

type ContextMenuAction = {
    key: 'mark-unread' | 'toggle-mark' | 'delete';
    label: string;
};

const contextMenuVisible = ref(false);
const contextMenuPosition = ref({ top: 0, left: 0 });
const contextMenuRef = ref<HTMLDivElement | null>(null);
const CONTEXT_MENU_WIDTH = 140;
const CONTEXT_MENU_ITEM_HEIGHT = 36;
const CONTEXT_MENU_PADDING = 8;

const contextMenuActions = computed<ContextMenuAction[]>(() => {
    const actions = props.session.swipeActions ?? [];
    return actions.map((key) => {
        if (key === 'mark-unread') {
            return { key, label: t('标记未读') };
        }
        if (key === 'toggle-mark') {
            return { key, label: props.session.marked ? t('取消标记') : t('标记') };
        }
        return { key, label: t('删除') };
    });
});

const closeContextMenu = () => {
    contextMenuVisible.value = false;
};

const handleWindowInteractionForMenu = (event: Event) => {
    if (event.type === 'keydown' && (event as KeyboardEvent).key !== 'Escape') {
        return;
    }
    if ((event.type === 'mousedown' || event.type === 'wheel') && contextMenuRef.value) {
        const target = event.target as Node | null;
        if (target && contextMenuRef.value.contains(target)) {
            return;
        }
    }
    closeContextMenu();
};

const bindContextMenuOutsideListeners = () => {
    window.addEventListener('mousedown', handleWindowInteractionForMenu, true);
    window.addEventListener('wheel', handleWindowInteractionForMenu, true);
    window.addEventListener('resize', handleWindowInteractionForMenu, true);
    window.addEventListener('keydown', handleWindowInteractionForMenu, true);
};

const unbindContextMenuOutsideListeners = () => {
    window.removeEventListener('mousedown', handleWindowInteractionForMenu, true);
    window.removeEventListener('wheel', handleWindowInteractionForMenu, true);
    window.removeEventListener('resize', handleWindowInteractionForMenu, true);
    window.removeEventListener('keydown', handleWindowInteractionForMenu, true);
};

watch(contextMenuVisible, (visible) => {
    if (visible) {
        bindContextMenuOutsideListeners();
    } else {
        unbindContextMenuOutsideListeners();
    }
});

onUnmounted(() => {
    unbindContextMenuOutsideListeners();
});

const handleContextMenu = (event: MouseEvent) => {
    if (isDisabled.value || isRinging.value) {
        return;
    }

    if (contextMenuActions.value.length === 0) {
        return;
    }

    event.preventDefault();

    const menuHeight = contextMenuActions.value.length * CONTEXT_MENU_ITEM_HEIGHT + CONTEXT_MENU_PADDING * 2;
    const maxLeft = window.innerWidth - CONTEXT_MENU_WIDTH - 4;
    const maxTop = window.innerHeight - menuHeight - 4;

    contextMenuPosition.value = {
        left: Math.min(Math.max(event.clientX, 4), Math.max(maxLeft, 4)),
        top: Math.min(Math.max(event.clientY, 4), Math.max(maxTop, 4)),
    };
    contextMenuVisible.value = true;
};

const handleContextMenuAction = (key: ContextMenuAction['key']) => {
    closeContextMenu();
    if (key === 'mark-unread') {
        emit('mark-unread');
        return;
    }
    if (key === 'toggle-mark') {
        emit('toggle-mark');
        return;
    }
    emit('delete');
};
</script>

<style scoped>
.pc-session-item {
    position: relative;
    display: flex;
    align-items: center;
    padding: 14px 16px;
    min-height: 76px;
    box-sizing: border-box;
    cursor: pointer;
    border-bottom: 1px solid #f5f5f5;
    transition: background-color 0.2s;
}

.pc-session-item:hover {
    background: #fafafa;
}

.pc-session-item.is-non-clickable {
    cursor: default;
}

.pc-session-item.is-non-clickable:hover {
    background: #fff;
}

.pc-session-item.active {
    background: rgb(242, 246, 255);
}

.marked-icon {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    margin-left: auto;
}

.avatar-wrapper {
    position: relative;
    margin-right: 12px;
    flex-shrink: 0;
}

.avatar-badge {
    position: absolute;
    top: -6px;
    right: -6px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    box-sizing: border-box;
    background: #ff4d4f;
    color: #fff;
    font-size: 12px;
    line-height: 14px;
    border-radius: 999px;
    text-align: center;
    white-space: nowrap;
    border: 1px solid #fff;
    z-index: 2;
}

.avatar-badge.is-single {
    width: 16px;
    min-width: 16px;
    padding: 0;
    border-radius: 50%;
}

.avatar-shell {
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
}

.avatar-shell.is-ringing {
    padding: 3px;
}

.avatar {
    width: 40px;
    height: 40px;
    border-radius: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 16px;
    flex-shrink: 0;
    overflow: hidden;
}

.avatar-image {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: inherit;
    display: block;
}

.avatar.is-ringing {
    border-radius: 50%;
}

.info {
    position: relative;
    flex: 1;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

.info.is-ringing {
    padding-right: 92px;
}

.top-row,
.bottom-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 8px;
}

.top-row {
    margin-bottom: 6px;
}

.middle-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 4px;
    min-width: 0;
}

.middle-tag {
    font-size: 12px;
    line-height: 16px;
    color: #666;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}

.name-row {
    display: flex;
    align-items: center;
    gap: 6px;
    flex: 1;
    min-width: 0;
}

.top-row.is-single-row {
    margin-bottom: 0;
}

.name {
    font-size: 14px;
    color: #333;
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    flex: 1;
    min-width: 0;
}

.meta-info {
    display: flex;
    align-items: center;
    flex-shrink: 0;
    gap: 4px;
}

.meta-info.status-meta {
    color: #0ABF77;
    min-width: 0;
    max-width: 58%;
}

.meta-info.is-ringing {
    position: absolute;
    top: 50%;
    right: 0;
    transform: translateY(-50%);
    z-index: 1;
}

.status-icon {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    filter: invert(56%) sepia(73%) saturate(542%) hue-rotate(106deg) brightness(92%) contrast(93%);
}

.status-text {
    font-size: 12px;
    line-height: 18px;
    color: #0ABF77;
    white-space: nowrap;
}

.accept-btn {
    min-width: 76px;
    height: 30px;
    padding: 0 12px;
    border: none;
    border-radius: 15px;
    background: #0ABF77;
    color: #fff;
    font-size: 12px;
    font-weight: 500;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.source {
    font-size: 11px;
    color: #666;
    background: #f0f0f0;
    padding: 1px 6px;
    border-radius: 3px;
}

.time {
    font-size: 12px;
    color: #999;
    flex-shrink: 0;
}

.msg {
    font-size: 12px;
    color: #666;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    flex: 1;
    min-width: 0;
}

.msg-placeholder {
    visibility: hidden;
}

.status-hint {
    font-size: 12px;
    line-height: 18px;
    color: #666;
    flex-shrink: 0;
    white-space: nowrap;
}

.badge {
    background: #ff4d4f;
    color: #fff;
    font-size: 12px;
    padding: 0 6px;
    border-radius: 10px;
    line-height: 16px;
    height: 16px;
    margin-left: 8px;
    flex-shrink: 0;
}

.session-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(169.56deg, rgba(255, 255, 255, 0.95) -9.58%, rgba(204, 226, 255, 0.95) 346.62%);
    color: #4E5461;
    font-size: 12px;
    font-weight: 500;
    z-index: 2;
    pointer-events: none;
}

.session-overlay-icon {
    width: 16px;
    height: 16px;
    margin-right: 6px;
    flex-shrink: 0;
}

.session-overlay-text {
    line-height: 16px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: calc(100% - 40px);
}
</style>

<style>
.pc-session-context-menu {
    position: fixed;
    z-index: 9999;
    min-width: 140px;
    padding: 4px 0;
    background: #fff;
    border-radius: 6px;
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.12), 0 0 1px rgba(0, 0, 0, 0.06);
    display: flex;
    flex-direction: column;
}

.pc-session-context-menu-item {
    display: flex;
    align-items: center;
    height: 36px;
    padding: 0 16px;
    border: none;
    background: transparent;
    color: #333;
    font-size: 13px;
    text-align: left;
    cursor: pointer;
    white-space: nowrap;
}

.pc-session-context-menu-item:hover {
    background: #f5f7fa;
}

.pc-session-context-menu-item.danger {
    color: #ff4d4f;
}
</style>
