import React, { useState, useEffect, useRef } from 'react';
import AliRtcEngine, { AliRtcSubscribeState, AliRtcVideoTrack,AliRtcSdkChannelProfile } from 'aliyun-rtc-sdk';
import { ToastContainer, toast } from 'react-toastify';

// 辅助函数
function hex(buffer: ArrayBuffer): string {
    const hexCodes = [];
    const view = new DataView(buffer);
    for (let i = 0; i < view.byteLength; i += 4) {
        const value = view.getUint32(i);
        const stringValue = value.toString(16);
        const padding = '00000000';
        const paddedValue = (padding + stringValue).slice(-padding.length);
        hexCodes.push(paddedValue);
    }
    return hexCodes.join('');
}

async function generateToken(
    appId: string,
    appKey: string,
    channelId: string,
    userId: string,
    timestamp: number
): Promise<string> {
    const encoder = new TextEncoder();
    const data = encoder.encode(`${appId}${appKey}${channelId}${userId}${timestamp}`);
    const hash = await crypto.subtle.digest('SHA-256', data);
    return hex(hash);
}

function showToast(type: 'info' | 'success' | 'error', message: string): void {
    switch(type) {
        case 'info':
            toast.info(message);
            break;
        case 'success':
            toast.success(message);
            break;
        case 'error':
            toast.error(message);
            break;
    }
}

const appId = 'a5842c2a-d94a-43be-81de-1fdb712476e1';
const appKey = 'b71d65f4f84c450f6f058f4ad507bd42';

export const RTCPage = () => {
    const [channelId, setChannelId] = useState<string>('');
    const [userId, setUserId] = useState<string>('');
    const [isJoined, setIsJoined] = useState<boolean>(false);
    const aliRtcEngine = useRef<AliRtcEngine | null>(null);
    const remoteVideoElMap = useRef<Record<string, HTMLVideoElement>>({});
    const remoteVideoContainer = useRef<HTMLDivElement>(null);

    function removeRemoteVideo(userId: string, type: 'camera' | 'screen' = 'camera') {
        const vid = `${type}_${userId}`;
        const el = remoteVideoElMap.current[vid];
        if (el) {
            aliRtcEngine.current!.setRemoteViewConfig(null, userId, type === 'camera' ? AliRtcVideoTrack.AliRtcVideoTrackCamera : AliRtcVideoTrack.AliRtcVideoTrackScreen);
            el.pause();
            remoteVideoContainer.current?.removeChild(el);
            delete remoteVideoElMap.current[vid];
        }
    }

    function listenEvents() {
        if (!aliRtcEngine.current) {
            return;
        }
        aliRtcEngine.current.on('remoteUserOnLineNotify', (userId: string, elapsed: number) => {
            console.log(`用户 ${userId} 加入频道，耗时 ${elapsed} 秒`);
            showToast('info', `用户 ${userId} 上线`);
        });

        aliRtcEngine.current.on('remoteUserOffLineNotify', (userId, reason) => {
            console.log(`用户 ${userId} 离开频道，原因码: ${reason}`);
            showToast('info', `用户 ${userId} 下线`);
            removeRemoteVideo(userId, 'camera');
            removeRemoteVideo(userId, 'screen');
        });

        aliRtcEngine.current.on('bye', (code) => {
            console.log(`bye, code=${code}`);
            showToast('info', `您已离开频道，原因码: ${code}`);
        });

        aliRtcEngine.current.on('videoSubscribeStateChanged', (
            userId: string,
            oldState: AliRtcSubscribeState,
            newState: AliRtcSubscribeState,
            interval: number,
            channelId: string
        ) => {
            console.log(`频道 ${channelId} 远端用户 ${userId} 订阅状态由 ${oldState} 变为 ${newState}`);
            const vid = `camera_${userId}`;
            if (newState === 3) {
                const video = document.createElement('video');
                video.autoplay = true;
                video.className = 'w-80 h-45 mr-2 mb-2 bg-black';
                remoteVideoElMap.current[vid] = video;
                remoteVideoContainer.current?.appendChild(video);
                aliRtcEngine.current!.setRemoteViewConfig(video, userId, AliRtcVideoTrack.AliRtcVideoTrackCamera);
            } else if (newState === 1) {
                removeRemoteVideo(userId, 'camera');
            }
        });

        aliRtcEngine.current.on('screenShareSubscribeStateChanged', (
            userId: string,
            oldState: AliRtcSubscribeState,
            newState: AliRtcSubscribeState,
            interval: number,
            channelId: string
        ) => {
            console.log(`频道 ${channelId} 远端用户 ${userId} 屏幕流的订阅状态由 ${oldState} 变为 ${newState}`);
            const vid = `screen_${userId}`;
            if (newState === 3) {
                const video = document.createElement('video');
                video.autoplay = true;
                video.className = 'w-80 h-45 mr-2 mb-2 bg-black';
                remoteVideoElMap.current[vid] = video;
                remoteVideoContainer.current?.appendChild(video);
                aliRtcEngine.current!.setRemoteViewConfig(video, userId, AliRtcVideoTrack.AliRtcVideoTrackScreen);
            } else if (newState === 1) {
                removeRemoteVideo(userId, 'screen');
            }
        });
    }

    const handleLoginSubmit = async (e: React.FormEvent) => {
        e.preventDefault();
        const timestamp = Math.floor(Date.now() / 1000) + 3600 * 3;

        if (!channelId || !userId) {
            showToast('error', '数据不完整');
            return;
        }

        const engine = AliRtcEngine.getInstance();
        aliRtcEngine.current = engine;
        listenEvents();

        try {
            const token = await generateToken(appId, appKey, channelId, userId, timestamp);
            aliRtcEngine.current!.setChannelProfile(AliRtcSdkChannelProfile.AliRtcSdkCommunication);
            await aliRtcEngine.current.joinChannel(
                {
                    channelId,
                    userId,
                    appId,
                    token,
                    timestamp,
                },
                userId
            );
            showToast('success', '加入频道成功');
            setIsJoined(true);
            aliRtcEngine.current!.setLocalViewConfig('localPreviewer', AliRtcVideoTrack.AliRtcVideoTrackCamera);
        } catch (error) {
            console.log('加入频道失败', error);
            showToast('error', '加入频道失败');
        }
    };

    const handleLeaveClick = async () => {
        Object.keys(remoteVideoElMap.current).forEach(vid => {
            const arr = vid.split('_');
            removeRemoteVideo(arr[1], arr[0] as 'screen' | 'camera');
        });
        if (aliRtcEngine.current) {
            await aliRtcEngine.current.stopPreview();
            await aliRtcEngine.current.leaveChannel();
            aliRtcEngine.current.destroy();
            aliRtcEngine.current = null;
        }
        setIsJoined(false);
        showToast('info', '已离开频道');
    };

    useEffect(() => {
        AliRtcEngine.setLogLevel(0);
    }, []);

    return (
        <div className="container p-2">
            <h1 className="text-2xl font-bold mb-4">aliyun-rtc-sdk 快速开始</h1>

            <ToastContainer
                position="top-right"
                autoClose={5000}
                hideProgressBar={false}
                newestOnTop={false}
                closeOnClick
                rtl={false}
                pauseOnFocusLoss
                draggable
                pauseOnHover
            />

            <div className="flex flex-wrap -mx-2 mt-6">
                <div className="w-full md:w-1/2 px-2 mb-4">
                    <form id="loginForm" onSubmit={handleLoginSubmit}>
                        <div className="mb-2">
                            <label htmlFor="channelId" className="block text-gray-700 text-sm font-bold mb-2">频道号</label>
                            <input
                                className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
                                id="channelId"
                                type="text"
                                value={channelId}
                                onChange={(e) => setChannelId(e.target.value)}
                            />
                        </div>
                        <div className="mb-2">
                            <label htmlFor="userId" className="block text-gray-700 text-sm font-bold mb-2">用户ID</label>
                            <input
                                className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
                                id="userId"
                                type="text"
                                value={userId}
                                onChange={(e) => setUserId(e.target.value)}
                            />
                        </div>
                        <button
                            id="joinBtn"
                            type="submit"
                            className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded mb-2"
                            disabled={isJoined}
                        >
                            加入频道
                        </button>
                        <button
                            id="leaveBtn"
                            type="button"
                            className="bg-gray-500 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded mb-2"
                            disabled={!isJoined}
                            onClick={handleLeaveClick}
                        >
                            离开频道
                        </button>
                    </form>

                    <div className="mt-6">
                        <h4 className="text-lg font-bold mb-2">本地预览</h4>
                        <video
                            id="localPreviewer"
                            muted
                            className="w-80 h-45 mr-2 mb-2 bg-black"
                        ></video>
                    </div>
                </div>
                <div className="w-full md:w-1/2 px-2">
                    <h4 className="text-lg font-bold mb-2">远端用户</h4>
                    <div id="remoteVideoContainer" ref={remoteVideoContainer}></div>
                </div>
            </div>
        </div>
    );
};

    
