import { formatTime, formatTimestamp, toggleElement, toggleButtonState } from '../../shared/utils.js';
import { mockCallSession } from '../models.js';
import chatMessage from '../chat/chatmessage.js';
import store from '../store.js';
import {
    buildUserCountLabel,
    createUserEntryElement,
    getCallTitle,
    getMediaStatusMeta,
    getNetworkQualityDisplay,
    getRemoteVideoPlaceholderText
} from './renderer-ui.js';
import { renderChatMessagesInto } from '../chat/renderer-chat.js';
import {
    updateParticipantTileName as syncParticipantTileName,
    updateParticipantTilePlaceholder
} from '../participants/renderer-participant-grid.js';
import {
    adjustVideoSize,
    clearParticipantGrid,
    getVideoResolution,
    removeParticipantTile,
    renderParticipantStreamMedia,
    renderSingleRemoteStreamMedia
} from '../media/renderer-media.js';
import { createLogger } from '../../shared/logger.js';

const logger = createLogger('renderer');

const GRID_LAYOUT = {
    maxColumns: 3,
    breakpoints: [
        { maxParticipants: 1, template: '1fr' },
        { maxParticipants: 4, template: 'repeat(2, 1fr)' }
    ],
    defaultTemplate: 'repeat(3, 1fr)'
};

function getGridTemplateColumns(participantCount) {
    for (const bp of GRID_LAYOUT.breakpoints) {
        if (participantCount <= bp.maxParticipants) {
            return bp.template;
        }
    }
    return GRID_LAYOUT.defaultTemplate;
}

class UIRenderer {
    constructor(stateManager) {
        this.stateManager = stateManager;
        this.unsubscribe = stateManager.subscribe(this.render.bind(this));

        this.elements = {
            header: document.querySelector('header'),
            footer: document.querySelector('footer'),
            participantGrid: document.getElementById('participantGrid'),
            headerTitle: document.getElementById('headerTitle'),
            callDuration: document.getElementById('callDuration'),
            encryptionBadge: document.getElementById('encryptionBadge'),
            unreadBadge: document.getElementById('unreadBadge'),
            remoteNetworkIndicator: document.getElementById('remoteNetworkIndicator'),
            remoteNetworkQuality: document.getElementById('remoteNetworkQuality'),

            remoteVideo: document.getElementById('remoteVideo'),
            remoteVideoPlaceholder: document.getElementById('remoteVideoPlaceholder'),
            networkStatus: document.getElementById('networkStatus'),
            networkStatusText: document.getElementById('networkStatusText'),
            connectingOverlay: document.getElementById('connectingOverlay'),

            localVideo: document.getElementById('localVideo'),
            localVideoPlaceholder: document.getElementById('localVideoPlaceholder'),
            localAudioWave: document.getElementById('localAudioWave'),
            localInitials: document.getElementById('localInitials'),

            sidebar: document.getElementById('sidebar'),
            chatContent: document.getElementById('chatContent'),
            userList: document.getElementById('userList'),
            localMediaStatus: document.getElementById('localMediaStatus'),
            localMuteIcon: document.querySelector('[data-field="localUser.muteIcon"]'),
            userCountDisplay: document.getElementById('userCountDisplay'),
            micBtn: document.getElementById('micBtn'),
            videoBtn: document.getElementById('videoBtn'),
            recordBtn: document.getElementById('recordBtn'),
            connectionQuality: document.getElementById('connectionQuality')
        };

        this.bindEventListeners();

        this.unsubscribe = stateManager.subscribe(this.render.bind(this));
        this.messageUnsubscribe = chatMessage.subscribe(this.renderMessageState.bind(this));
        this.render(this.stateManager.getState(), { type: 'INIT' });

        window.addEventListener('resize', () => {
            if (this.elements.remoteVideo && this.elements.remoteVideo.srcObject) {
                const stream = this.elements.remoteVideo.srcObject;
                const videoTracks = stream.getVideoTracks();
                if (videoTracks.length > 0) {
                    adjustVideoSize(this.elements.remoteVideo, getVideoResolution(videoTracks[0]));
                }
            }
        });
    }

    renderMessageState(messageState, changes) {
        switch (changes.type) {
            case 'NEW_MESSAGE':
                this.renderChatMessages(messageState.messages);
                this.renderUnreadCount(changes.unreadCount);
                break;
            case 'SIDEBAR_TOGGLE':
                this.renderSidebar(changes.isOpen);
                if (changes.isOpen) {
                    this.renderUnreadCount(0);
                } else {
                    this.renderUnreadCount(changes.unreadCount);
                }
                break;
        }
    }

    bindEventListeners() {
    }

    /**
     * 婵炴挸寮堕悡瀣棘鐟欏嫮銆?- 闁哄秷顫夊畵渚€鎮╅懜纰樺亾娴ｇ缍侀柛鏍ㄧ墬濞插潡寮惂鐕?
     * @param {Object} state - 鐟滅増鎸告晶鐘虫償閺冨倹鏆忛柣妯垮煐閳?
     * @param {Object} changes - 闁绘鍩栭埀顑跨瑜板宕犻弽褜鍤犻悹?
     */
    render(state, changes) {
        switch (changes.type) {
            case 'INIT':
                this.renderRemoteVideo(state.session.remoteUser);
                this.renderLocalVideo(state.session.localUser, state.localStream);
                this.renderControlButtons(state.session.localUser.mediaState);
                this.renderChatMessages(chatMessage.getMessageState().messages);
                this.renderUserList(state.session.localUser, state.session.remoteUser, state.participants);
                this.renderHeader(state.session);
                if (this.elements.remoteVideoPlaceholder) {
                    if (state.remoteStream) {
                        this.elements.remoteVideoPlaceholder.classList.add('hidden');
                    } else {
                        this.elements.remoteVideoPlaceholder.classList.remove('hidden');
                    }
                }
                break;
            case 'DURATION_UPDATE':
                this.renderCallDuration(changes.duration);
                break;
            case 'LOCAL_MEDIA_CHANGE':
                this.renderControlButtons(state.session.localUser.mediaState);
                this.renderLocalVideo(state.session.localUser, state.localStream);
                this.renderLocalUserStatus(state.session.localUser);
                this.renderUserList(state.session.localUser, state.session.remoteUser, state.participants);
                break;
            case 'LOCAL_STREAM_OBTAINED':
                this.renderLocalStream(state.localStream);
                this.renderLocalVideo(state.session.localUser, state.localStream);
                break;
            case 'REMOTE_STREAM_OBTAINED':
                this.renderRemoteStream(changes.stream, changes.connectionId, changes.isHost);
                if (this.elements.connectingOverlay) {
                    this.elements.connectingOverlay.classList.add('hidden');
                }
                break;
            case 'REMOTE_MEDIA_CHANGE':
                this.renderRemoteVideo(state.session.remoteUser);
                this.renderUserList(state.session.localUser, state.session.remoteUser, state.participants);
                if (changes.participantId && state.session.localUser.isHost) {
                    const pInfo = state.participants[changes.participantId];
                    const showPlaceholder = pInfo ? !pInfo.mediaState.video : true;
                    this.renderParticipantVideoPlaceholder(changes.participantId, showPlaceholder);
                }
                break;
            case 'USER_LIST_UPDATE':
                this.renderUserList(changes.localUser, changes.remoteUser, state.participants);
                break;
            case 'PARTICIPANTS_UPDATE':
                this.renderUserList(state.session.localUser, state.session.remoteUser, changes.participants || state.participants);
                this.syncParticipantTileNames(changes.participants || state.participants);
                break;
            case 'NETWORK_CHANGE':
                this.renderNetworkStatus(changes.quality);
                break;
            case 'CALL_STATUS_CHANGE':
                this.renderCallStatus(changes.status);
                break;
            case 'CALL_ENDED':
                this.renderCallEnded();
                break;
            case 'PARTICIPANT_LEFT':
                this.renderParticipantLeft(changes.connectionId);
                break;
            case 'RESOLUTION_CHANGED':
                this.renderResolutionChanged(changes.resolution);
                break;
        }
    }

    renderCallStatus(status) {
        if (this.elements.connectingOverlay) {
            if (status === 'connecting') {
                this.elements.connectingOverlay.classList.remove('hidden');
            } else {
                this.elements.connectingOverlay.classList.add('hidden');
            }
        }
    }

    renderHeader(session) {

        this.renderHeaderTitle();
        if (this.elements.encryptionBadge) {
            toggleElement(this.elements.encryptionBadge, session.isEncrypted);
        }

        if (this.elements.remoteNetworkIndicator) {
            this.elements.remoteNetworkIndicator.classList.remove('hidden');
        }
        if (this.elements.remoteNetworkQuality) {
            this.elements.remoteNetworkQuality.classList.remove('hidden');
        }

        this.renderCallDuration(session.duration);
    }
    renderHeaderTitle() {
        if (this.elements.headerTitle) {
            const connectionId = store.getConnectionId() || '';
            this.elements.headerTitle.textContent = getCallTitle(connectionId);

        }
    }

    renderCallDuration(duration) {
        if (this.elements.callDuration) {
            this.elements.callDuration.textContent = formatTime(duration);
        }
    }

    renderResolutionChanged(resolution) {
        if (!resolution) return;

        const options = document.querySelectorAll('.resolution-option');
        options.forEach(btn => {
            const btnRes = btn.dataset.resolution;
            const isActive = (resolution.height >= 1440 && btnRes === '1440') ||
                             (resolution.height >= 1080 && resolution.height < 1440 && btnRes === '1080') ||
                             (resolution.height >= 720 && resolution.height < 1080 && btnRes === '720') ||
                             (resolution.height < 720 && btnRes === '480');
            btn.classList.toggle('active', isActive);
        });

        const currentResText = document.getElementById('currentResolutionText');
        if (currentResText) {
            currentResText.textContent = `当前: ${resolution.label}`;
        }
    }

    renderRemoteVideo(remoteUser) {
        this.renderUserList(
            this.stateManager.getState().session.localUser,
            remoteUser,
            this.stateManager.getState().participants
        );

        if (this.elements.remoteVideoPlaceholder) {
            const shouldShowPlaceholder = !remoteUser.mediaState.video;
            const placeholderText = getRemoteVideoPlaceholderText(!shouldShowPlaceholder);
            toggleElement(this.elements.remoteVideoPlaceholder, shouldShowPlaceholder);

            if (this.elements.remoteVideo) {
                this.elements.remoteVideo.style.opacity = shouldShowPlaceholder ? '0' : '1';
            }

            const placeholderContent = this.elements.remoteVideoPlaceholder.querySelector('.text-center');
            if (placeholderContent) {
                const titleElement = placeholderContent.querySelector('p.text-white.text-lg.font-medium');
                const subtitleElement = placeholderContent.querySelector('p.text-sm.text-gray-400');

                if (titleElement) {
                    titleElement.textContent = placeholderText.title;
                }
                if (subtitleElement) {
                    subtitleElement.textContent = placeholderText.subtitle;
                }
            }
        }

        this.renderNetworkStatus(remoteUser.networkQuality);
        this.renderHeaderNetworkStatus(remoteUser.networkQuality);
    }

    renderHeaderNetworkStatus(networkQuality) {
        if (this.elements.remoteNetworkQuality) {
            const textElement = this.elements.remoteNetworkQuality.querySelector('span');
            const iconElement = this.elements.remoteNetworkQuality.querySelector('i');

            if (textElement && iconElement) {
                const display = getNetworkQualityDisplay(networkQuality);
                textElement.textContent = display.label;
                iconElement.className = display.headerIconClass;
            }
        }
    }

    renderLocalVideo(localUser, localStream) {
        if (this.elements.localVideoPlaceholder) {
            const shouldShowPlaceholder = !localStream || !localUser.mediaState.video;
            toggleElement(this.elements.localVideoPlaceholder, shouldShowPlaceholder);
        }

        if (this.elements.localAudioWave) {
            toggleElement(this.elements.localAudioWave, localUser.mediaState.isSpeaking);
        }

        this.renderLocalUserStatus(localUser);
    }

    renderLocalStream(stream) {
        if (this.elements.localVideo && stream) {
            this.elements.localVideo.srcObject = stream;
            this.elements.localVideo.autoplay = true;
            this.elements.localVideo.muted = true;
            logger.debug('srcObject set successfully:', this.elements.localVideo.srcObject);

            if (this.elements.disconnectedOverlay) {
                this.elements.disconnectedOverlay.classList.add('hidden');
            }
        } else {
            logger.error('Either localVideo element or stream is missing');
        }
    }

    renderRemoteStream(stream, connectionId, isHost) {
        if (isHost && connectionId) {
            this.renderParticipantStream(stream, connectionId);
        } else {
            this.renderSingleRemoteStream(stream);
        }
    }

    renderParticipantStream(stream, connectionId) {
        const participantInfo = this.stateManager.getState().participants[connectionId];
        renderParticipantStreamMedia({
            grid: this.elements.participantGrid,
            stream,
            connectionId,
            displayName: participantInfo?.name,
            getGridTemplateColumns,
            remoteVideo: this.elements.remoteVideo,
            connectingOverlay: this.elements.connectingOverlay,
            remoteVideoPlaceholder: this.elements.remoteVideoPlaceholder
        });
    }
    renderParticipantVideoPlaceholder(participantId, showPlaceholder) {
        const grid = this.elements.participantGrid;
        if (!grid) return;
        updateParticipantTilePlaceholder(grid, participantId, showPlaceholder);
        logger.debug(`Updated placeholder for participant ${participantId}: ${showPlaceholder ? 'shown' : 'hidden'}`);
    }

    syncParticipantTileNames(participants) {
        if (!participants) return;
        const grid = this.elements.participantGrid;
        if (!grid) return;
        for (const [participantId, pInfo] of Object.entries(participants)) {
            this.updateParticipantTileName(participantId, pInfo.name);
        }
    }

    updateParticipantTileName(participantId, name) {
        const grid = this.elements.participantGrid;
        if (!grid) return;
        syncParticipantTileName(grid, participantId, name);
        if (name) {
            logger.debug(`Updated tile name for participant ${participantId}: ${name}`);
        }
    }

    renderSingleRemoteStream(stream) {
        renderSingleRemoteStreamMedia({
            remoteVideo: this.elements.remoteVideo,
            stream,
            disconnectedOverlay: this.elements.disconnectedOverlay,
            remoteVideoPlaceholder: this.elements.remoteVideoPlaceholder,
            connectingOverlay: this.elements.connectingOverlay
        });
    }

    renderLocalUserStatus(localUser) {
        const mediaMeta = getMediaStatusMeta(localUser.mediaState);

        if (this.elements.localMediaStatus) {
            this.elements.localMediaStatus.textContent = mediaMeta.text;
            this.elements.localMediaStatus.className = mediaMeta.className;
        }

        if (this.elements.localMuteIcon) {
            if (mediaMeta.showMuteIcon) {
                this.elements.localMuteIcon.classList.remove('hidden');
                this.elements.localMuteIcon.className = mediaMeta.muteIconClass;
            } else {
                this.elements.localMuteIcon.classList.add('hidden');
            }
        }
    }

    renderUserList(localUser, remoteUser, participants) {
        if (!this.elements.userList) return;

        const participantsMap = participants || {};
        const participantCount = Object.keys(participantsMap).length;
        const userCount = 1 + participantCount;

        if (this.elements.userCountDisplay) {
            this.elements.userCountDisplay.textContent = buildUserCountLabel(userCount);
        }

        this.elements.userList.innerHTML = '';
        this.elements.userList.appendChild(createUserEntryElement({
            user: localUser,
            role: 'local'
        }));

        if (participantCount > 0) {
            for (const [participantId, participant] of Object.entries(participantsMap)) {
                this.elements.userList.appendChild(createUserEntryElement({
                    user: participant,
                    role: participant.role === 'host' ? 'host' : 'participant',
                    id: participantId
                }));
            }
        } else if (remoteUser.status !== 'offline') {
            this.elements.userList.appendChild(createUserEntryElement({
                user: remoteUser,
                role: 'remote'
            }));
        }
    }

    renderControlButtons(mediaState) {
        if (this.elements.micBtn) {
            toggleButtonState(this.elements.micBtn, !mediaState.audio);
        }

        if (this.elements.videoBtn) {
            toggleButtonState(this.elements.videoBtn, !mediaState.video);
        }

        if (this.elements.recordBtn) {
            toggleButtonState(this.elements.recordBtn, mediaState.recording);
        }
    }

    renderChatMessages(messages) {
        renderChatMessagesInto(this.elements.chatContent, messages, formatTimestamp);
    }

    renderUnreadCount(count) {
        if (this.elements.unreadBadge) {
            if (count > 0) {
                this.elements.unreadBadge.textContent = count;
                this.elements.unreadBadge.classList.remove('hidden');
            } else {
                this.elements.unreadBadge.classList.add('hidden');
            }
        }
    }

    renderSidebar(isOpen) {
        if (this.elements.sidebar) {
            if (isOpen) {
                this.elements.sidebar.classList.remove('hidden');
            } else {
                this.elements.sidebar.classList.add('hidden');
            }
        }
    }

    renderNetworkStatus(quality) {
        const display = getNetworkQualityDisplay(quality);

        if (this.elements.networkStatus && this.elements.networkStatusText) {
            toggleElement(this.elements.networkStatus, true);

            const networkStatus = this.elements.networkStatus;
            const networkStatusText = this.elements.networkStatusText;
            const existingIcon = networkStatus.querySelector('i');
            if (existingIcon) {
                existingIcon.remove();
            }

            const icon = document.createElement('i');
            icon.className = display.statusIconClass;
            networkStatusText.textContent = display.label;
            networkStatusText.className = display.statusTextClass;
            networkStatus.insertBefore(icon, networkStatusText);
        }

        if (this.elements.connectionQuality) {
            this.elements.connectionQuality.textContent = `连接质量: ${display.label}`;
            this.elements.connectionQuality.className = `text-xs ${display.connectionTextClass}`;
        }

        this.updateHeaderNetworkIndicator(quality);
        this.renderHeaderNetworkStatus(quality);
    }

    updateHeaderNetworkIndicator(networkQuality) {
        if (!this.elements.remoteNetworkIndicator) return;
        this.elements.remoteNetworkIndicator.className = getNetworkQualityDisplay(networkQuality).indicatorClass;
    }

    renderCallEnded() {
        logger.debug('Call ended');
        clearParticipantGrid(this.elements.participantGrid);
        window.location.href = '/endcall/';
    }

    renderParticipantLeft(connectionId) {
        logger.debug(`Participant left: ${connectionId}, updating UI`);
        removeParticipantTile({
            grid: this.elements.participantGrid,
            connectionId,
            getGridTemplateColumns,
            remoteVideo: this.elements.remoteVideo,
            remoteVideoPlaceholder: this.elements.remoteVideoPlaceholder,
            remoteNetworkIndicator: this.elements.remoteNetworkIndicator
        });
    }

    destroy() {
        if (this.unsubscribe) {
            this.unsubscribe();
        }
        if (this.messageUnsubscribe) {
            this.messageUnsubscribe();
        }
    }
}

export default UIRenderer;
