const CACHE_NAME = 'v1';
importScripts('http://talk.kospo.co.kr:3000/static/js/module/stomp.js');

let sockJS = null;
let stompClient = null;
let reConnectAttempts = 0
let maxReconnectAttempts = 3
// 마스터 탭 변수
let connTab = null

let messageList = [];
let forceConnect = false;
// 서비스워커 체커 마지막 시간 변수
let lastHeartbeat = null;

/*재귀 함수 변수*/
let checker;
let connectLock = false;

let subscribe = null;

// indexeddb 데이터 조회
function getData(col, val) {
    return new Promise((resolve, reject) => {
        if (connTab[col] === val) {
            resolve(connTab);
        }
    })
}

// indexeddb 데이터 추가
function addData(obj) {
    connTab = obj;
}

function delData(tabId) {
    return new Promise((resolve, reject) => {
        messageList.forEach((message, idx) => {
            if (message.tabId === tabId) {
                messageList.splice(idx, 1);
            }
        })
        if (connTab) {
            if (connTab.tabId === tabId) {
                connTab = null
            }
        }

        resolve();
    })
}

async function getClientCount(url) {
    const allClients = await clients.matchAll({
        includeUncontrolled: true,
        type: 'window',
    });


    const cc = allClients.filter(client => client.url === url);
    console.log(cc, '해당 클라이언트가 하나만 나와야함')
    return cc.length;
}

// 클라이언트 에게 메시지 전달
async function hubToClients(message) {
    const allClients = await clients.matchAll({
        includeUncontrolled: true,
        type: 'window',
    });

    allClients.forEach(client => {
        client.postMessage(message);
    });
}

// 브라우저 종료시 소켓 연결 해지
async function disConnectWebSocket(message) {
    delData(message.tabId).then(() => {
        console.log('disConnect', connTab, message.tabId)
        if (connTab === null) {
            try {
                allClose();
                if (messageList.length !== 0) connectWebSocket(messageList[0])
            } catch (e) {
            }
        }
    })

    // 모든 클라이언트가 종료시 서비스워커 heartbeat 제거
    const allClients = await clients.matchAll({
        includeUncontrolled: true,
        type: 'window',
    });

    if(allClients.length === 1) {
        clearInterval(checker)
        checker = null;
    }
}

// 브라우저 종료시 소켓 연결 해지
async function kill() {
    console.log('service worker kill');
    connTab = null;
    messageList = [];
    clearInterval(checker)
    checker = null;
    allClose();
}

// 탭간 공유 웹소켓 연결 관리
async function connectWebSocket(message) {
    getClientCount(message.site).then((windowClientCount) => {
        if(windowClientCount === 1) {
            connTab = null
            messageList = []
        }

            lastHeartbeat = Date.now();

            if (connTab === null || sockJS.readyState !== 1) {

                if(sockJS !== null) {
                    if(sockJS.readyState === WebSocket.OPEN) {
                        allClose();
                    }
                }

                sockJS = new WebSocket(`ws://talk.kospo.co.kr:3000/stomp/ws`);
                // sockJS = new SockJS(
                //     `http://talk.kospo.co.kr:3000/stomp/talk`, {
                //         Authentication: message.encSabun
                //     }, {
                //         transports: ['websocket'],
                //         reconnectInterval: 500,
                //         reconnectDelay: 500,
                //     },
                // );

                if(sockJS !== WebSocket.CLOSED && sockJS !== WebSocket.CLOSING) {
                    stompClient = Stomp.over(sockJS);
                    stompClient.heartbeat.outgoing = 20000;
                    stompClient.heartbeat.incoming = 20000;
                    stompClient.debug = (e) => {
                        if (e.includes('ERROR') || e.includes('Exception') || e.includes('failed')) {
                            console.log(new Date().toString())
                            console.error('STOMP error:', e);

                        }
                    };

                    stompClient.connect({Authentication: message.encSabun, location: 'SW'}, function (frame) {
                        console.log('hub connect', message.tabId)
                        subscribe = stompClient.subscribe(`/exchange/hub.exchange/hub.${message.tabId}`, async function (content) {
                            const payload = JSON.parse(content.body);
                            hubToClients(payload)

                        })

                        /*사이트 정보 탭 아이디 저장*/
                        addData({
                            url: message.site,
                            tabId: message.tabId
                        })

                        /* 여러개 탭이 활성화시 방지용 서비스워커 체커*/
                        if(checker == null) {
                            /*테스트*/
                            checker = setInterval(() => {
                                // lastHeartbeat = Date.now();
                                // console.log('서비스워커 실행중', new Date())
                                hubToClients({type:"PING"})
                            }, 10000)
                        } else {
                            console.log('checker and reset is exist')
                        }


                        // 재연결 시도 초기화
                        reConnectAttempts = 0;
                    })
                }

                const baseDelay = 500
                sockJS.onclose = (e) => {
                    if(e.code !== 1000) {
                        const delay = Math.min(baseDelay * Math.pow(2, reConnectAttempts), 5000)
                        setTimeout(() => {
                            hubReconnect()
                            if(reConnectAttempts < maxReconnectAttempts) {
                                reConnectAttempts++;
                            } else {
                                console.log('[Service Worker Hub] Max Reconnect attempts reached.')
                            }
                        }, delay)
                    }

            }
        } else {
            console.log('hub socket is connected')
        }
    });
}

const hubReconnect = () => {
    allClose()
    clearInterval(checker)
    checker = null;
    hubToClients({type:'HUB_RECONNECT'});
    lastHeartbeat = Date.now();
}

// 서비스워커 설치
self.addEventListener('install', (event) => {
    console.log('SW: Installing...');
    event.waitUntil(
        self.skipWaiting(),
    );
});

// 서비스워커 활성화
self.addEventListener('activate', function activator(event) {
    // delData();
    event.waitUntil(
        self.clients.claim()
    );
})

// 클라이언트로부터의 메시지 처리 (연결 및 해지)
self.addEventListener('message', async (event) => {
    const message = event.data;
    switch (message.type) {
        case 'CONNECT':
            connectLock = false;
            messageList.push(message);
            connectWebSocket(message);
            break;
        case 'TAB_CLOSE':
            disConnectWebSocket(message);
            break;
        case "KILL" :
            kill();
            break;
        case 'PONG' :
            if (stompClient === null) {
                hubReconnect()
            }
            break;
        case "WAKEUP" :
            if (stompClient === null) {
                if (!connectLock) {
                    connectLock = true;
                    hubReconnect()
                }
            } else {
                if (!connectLock) {
                    hubToClients({type: "GETUP"})
                }

            }
            break;
        case 'HUB_RECONNECT_SUCCESS' :
            let suc = true;
            while (suc) {
                if (stompClient.connected) {
                    connectLock = false;
                    suc = false;
                }
                await sleep(100)
            }
            break;
        case 'FONT_CHANGE':
            hubToClients(message)
            break;
    }
});

const sleep = (delay) => {
    return new Promise(resolve => setTimeout(resolve, delay));
}

const allClose = () => {
    try{subscribe.unsubscribe()} catch(e) {}
    try{stompClient.disconnect()} catch(e) {}
    try{sockJS.close();} catch(e) {}
    stompClient = null;
    sockJS = null;
    subscribe = null;
}