if (/iPhone|iPad|iPod|Android/i.test(navigator.userAgent)) {
    let meta = document.createElement('meta')
    meta.name = 'viewport'
    meta.content = 'width=device-width, height=device-height, initial-scale=1.0, user-scalable=no, shrink-to-fit=yes'
    document.getElementsByTagName('head')[0].appendChild(meta)
}

const CANVAS = document.getElementById('canvas')
const STORAGE_DATA_SEPARATOR = '{bridge_data_separator}'
const STORAGE_KEYS_SEPARATOR = '{bridge_keys_separator}'
const STORAGE_VALUES_SEPARATOR = '{bridge_values_separator}'

// utils
window.unityInstance = null
const messageQueue = []
let progressBarFillingInterval = null
let progressBarCompleteFillingStarted = false

function sendMessageToUnity(name, value) {
    if (window.unityInstance !== null) {
        window.unityInstance.SendMessage('PlaygamaBridge', name, value)
    } else {
        messageQueue.push({ name, value })
    }
}

function flushMessageQueue() {
    while (messageQueue.length > 0) {
        const message = messageQueue.shift()
        if (window.unityInstance !== null) {
            window.unityInstance.SendMessage('PlaygamaBridge', message.name, message.value)
        }
    }
}

function onUnityLoadingProgressChanged(progress) {
    if (progress >= 1) {
        if (progressBarFillingInterval !== null) {
            clearInterval(progressBarFillingInterval)
            progressBarFillingInterval = null
        }
        bridge.game.setLoadingProgress(100)
        return
    }

    if (progressBarCompleteFillingStarted) {
        return
    }

    if (progress >= 0.9) {
        progressBarCompleteFillingStarted = true
        completeProgressBarFilling()
        return
    }

    bridge.game.setLoadingProgress(progress * 100)
}

function completeProgressBarFilling() {
    if (progressBarFillingInterval !== null) {
        return
    }

    let currentPercent = 90
    bridge.game.setLoadingProgress(currentPercent)
    progressBarFillingInterval = setInterval(() => {
        currentPercent++
        if (currentPercent > 99) {
            currentPercent = 99
        }

        bridge.game.setLoadingProgress(currentPercent)

        if (currentPercent >= 99) {
            clearInterval(progressBarFillingInterval)
            progressBarFillingInterval = null
            return
        }
    }, 500)
}

window.addEventListener('pointerdown', () => {
    window.focus()
    CANVAS.focus()
})

let bridgeScript = null
let bridgeTimeout = null
let bridgeLoaded = false

function addLocalBridge() {
    if (bridgeLoaded) return
    bridgeLoaded = true
    clearTimeout(bridgeTimeout)

    if (bridgeScript && bridgeScript.parentNode) {
        bridgeScript.onload = null
        bridgeScript.onerror = null
        bridgeScript.parentNode.removeChild(bridgeScript)
    }

    window.bridge = null
    window.playgamaBridge = null

    const scriptElement = document.createElement('script')
    scriptElement.src = './playgama-bridge.js'
    scriptElement.onload = function() {
        initializeBridge()
    }
    document.body.appendChild(scriptElement)
}

bridgeScript = document.createElement('script')
bridgeScript.src = 'https://bridge.playgama.com/v1/stable/playgama-bridge.js'
bridgeScript.onload = initializeBridge
bridgeScript.onerror = addLocalBridge

bridgeTimeout = setTimeout(() => {
    console.warn('CDN bridge failed to load within 2 seconds, loading local bridge')
    addLocalBridge()
}, 2000)

document.head.appendChild(bridgeScript)

function initializeBridge() {
    clearTimeout(bridgeTimeout)
    bridge.engine = 'unity'
    bridge
        .initialize()
        .then(() => {
            bridge.game.setLoadingProgress(0)
            bridge.advertisement.on('banner_state_changed', state => sendMessageToUnity('OnBannerStateChanged', state))
            bridge.advertisement.on('interstitial_state_changed', state => sendMessageToUnity('OnInterstitialStateChanged', state))
            bridge.advertisement.on('rewarded_state_changed', state => sendMessageToUnity('OnRewardedStateChanged', state))
            bridge.advertisement.on('advanced_banners_state_changed', state => sendMessageToUnity('OnAdvancedBannersStateChanged', state))
            bridge.game.on('visibility_state_changed', state => sendMessageToUnity('OnVisibilityStateChanged', state))
            bridge.platform.on('audio_state_changed', isEnabled => sendMessageToUnity('OnAudioStateChanged', isEnabled.toString()))
            bridge.platform.on('pause_state_changed', isPaused => sendMessageToUnity('OnPauseStateChanged', isPaused.toString()))

            let unityLoader = document.createElement('script')
            unityLoader.src = 'Build/609c2eae3e910f023591b11cbe42afc3.loader.js'
            unityLoader.onload = () => {
                createUnityInstance(
                    CANVAS,
                    {
                        dataUrl: 'Build/fdee49757bf8ab2cef872c393a1d1596.data.unityweb',
                        frameworkUrl: 'Build/cd228645fddf8e1800edba42a1ca27d7.framework.js.unityweb',
                        codeUrl: 'Build/9dbf322663d7cd8361fb402e25ce0838.wasm.unityweb',
                        streamingAssetsUrl: 'StreamingAssets',
                        companyName: 'TurtleGamesStudio',
                        productName: 'Battle of the Clones',
                        productVersion: '0.1',
                        // matchWebGLToCanvasSize: false, // Uncomment this to separately control WebGL canvas render size and DOM element size.
                        // devicePixelRatio: 1, // Uncomment this to override low DPI rendering on high DPI displays.
                    },
                    onUnityLoadingProgressChanged)
                    .then((unityInstance) => {
                        window.unityInstance = unityInstance
                        CANVAS.focus()
                        flushMessageQueue()
                    })
                    .catch((error) => {
                        console.error(error)
                    })
            }
            document.body.appendChild(unityLoader)
        })
        .catch(error => console.error(error))
}

// platform
window.getPlatformId = function() {
    return bridge.platform.id
}

window.getPlatformLanguage = function() {
    return bridge.platform.language
}

window.getPlatformPayload = function() {
    let payload = bridge.platform.payload
    if (typeof payload === 'string') {
        return payload
    } else {
        return ''
    }
}

window.getPlatformTld = function() {
    let tld = bridge.platform.tld
    if (typeof tld === 'string') {
        return tld
    } else {
        return ''
    }
}

window.getIsPlatformAudioEnabled = function() {
    return bridge.platform.isAudioEnabled.toString()
}

window.getIsPlatformGetAllGamesSupported = function() {
    return bridge.platform.isGetAllGamesSupported.toString()
}

window.getIsPlatformGetGameByIdSupported = function() {
    return bridge.platform.isGetGameByIdSupported.toString()
}

window.sendMessageToPlatform = function(message, options) {
    if (options) {
        options = JSON.parse(options)
    }

    bridge.platform.sendMessage(message, options)
}

window.sendCustomMessageToPlatform = function(id, options) {
    if (options) {
        options = JSON.parse(options)
    }

    bridge.platform.sendCustomMessage(id, options)
}

window.getServerTime = function() {
    bridge.platform.getServerTime()
        .then(result => {
            sendMessageToUnity('OnGetServerTimeCompleted', result.toString())
        })
        .catch(error => {
            sendMessageToUnity('OnGetServerTimeCompleted', 'false')
        })
}

window.getAllGames = function() {
    bridge.platform.getAllGames()
        .then(result => {
            sendMessageToUnity('OnGetAllGamesCompletedSuccess', JSON.stringify(result))
        })
        .catch(error => {
            sendMessageToUnity('OnGetAllGamesCompletedFailed')
        })
}

window.getGameById = function(options) {
    if (options) {
        options = JSON.parse(options)
    } else {
        options = {}
    }

    bridge.platform.getGameById(options)
        .then(result => {
            sendMessageToUnity('OnGetGameByIdCompletedSuccess', JSON.stringify(result))
        })
        .catch(error => {
            sendMessageToUnity('OnGetGameByIdCompletedFailed')
        })
}

// device
window.getDeviceType = function() {
    return bridge.device.type
}

window.getSafeArea = function() {
    return JSON.stringify(bridge.device.safeArea)
}


// player
window.getIsPlayerAuthorizationSupported = function() {
    return bridge.player.isAuthorizationSupported.toString()
}

window.getIsPlayerAuthorized = function() {
    return bridge.player.isAuthorized.toString()
}

window.getPlayerId = function() {
    if (bridge.player.id) {
        return bridge.player.id.toString()
    }

    return ''
}

window.getPlayerName = function() {
    if (bridge.player.name) {
        return bridge.player.name.toString()
    }

    return ''
}

window.getPlayerPhotos = function() {
    if (bridge.player.photos.length > 0) {
        return JSON.stringify(bridge.player.photos)
    }

    return ''
}

window.getPlayerExtra = function() {
    if (bridge.player.extra) {
        return JSON.stringify(bridge.player.extra)
    }

    return ''
}

window.authorizePlayer = function(options) {
    if (options) {
        options = JSON.parse(options)
    }

    bridge.player.authorize(options)
        .then(() => {
            sendMessageToUnity('OnAuthorizeCompleted', 'true')
        })
        .catch(error => {
            sendMessageToUnity('OnAuthorizeCompleted', 'false')
        })
}


// game
window.getVisibilityState = function() {
    return bridge.game.visibilityState
}


// storage
window.getStorageDefaultType = function() {
    return bridge.storage.defaultType
}

window.getIsStorageSupported = function(storageType) {
    return bridge.storage.isSupported(storageType).toString()
}

window.getIsStorageAvailable = function(storageType) {
    return bridge.storage.isAvailable(storageType).toString()
}

window.getStorageData = function(key, storageType) {
    let keys = key.split(STORAGE_KEYS_SEPARATOR)

    bridge.storage.get(keys, storageType, false)
        .then(data => {
            if (keys.length > 1) {
                let values = []

                for (let i = 0; i < keys.length; i++) {
                    let value = data[i]
                    if (value) {
                        if (typeof value !== 'string') {
                            value = JSON.stringify(value)
                        }

                        values.push(value)
                    } else {
                        values.push('')
                    }
                }

                sendMessageToUnity('OnGetStorageDataSuccess', `${key}${STORAGE_DATA_SEPARATOR}${values.join(STORAGE_VALUES_SEPARATOR)}`)
            } else {
                if (data[0]) {
                    if (typeof data[0] !== 'string') {
                        data = JSON.stringify(data[0])
                    }
                } else {
                    data = ''
                }

                sendMessageToUnity('OnGetStorageDataSuccess', `${key}${STORAGE_DATA_SEPARATOR}${data}`)
            }
        })
        .catch(error => {
            sendMessageToUnity('OnGetStorageDataFailed', key)
        })
}

window.setStorageData = function(key, value, storageType) {
    let keys = key.split(STORAGE_KEYS_SEPARATOR)
    let values = value.split(STORAGE_VALUES_SEPARATOR)

    bridge.storage.set(keys, values, storageType)
        .then(() => {
            sendMessageToUnity('OnSetStorageDataSuccess', key)
        })
        .catch(error => {
            sendMessageToUnity('OnSetStorageDataFailed', key)
        })
}

window.deleteStorageData = function(key, storageType) {
    let keys = key.split(STORAGE_KEYS_SEPARATOR)

    bridge.storage.delete(keys, storageType)
        .then(() => {
            sendMessageToUnity('OnDeleteStorageDataSuccess', key)
        })
        .catch(error => {
            sendMessageToUnity('OnDeleteStorageDataFailed', key)
        })
}


// advertisement
window.getInterstitialState = function() {
    if (bridge.advertisement.interstitialState) {
        return bridge.advertisement.interstitialState
    } else {
        return ''
    }
}

window.getIsBannerSupported = function() {
    return bridge.advertisement.isBannerSupported.toString()
}

window.getIsInterstitialSupported = function() {
    return bridge.advertisement.isInterstitialSupported.toString()
}

window.getMinimumDelayBetweenInterstitial = function() {
    return bridge.advertisement.minimumDelayBetweenInterstitial.toString()
}

window.setMinimumDelayBetweenInterstitial = function(options) {
    bridge.advertisement.setMinimumDelayBetweenInterstitial(options)
}

window.getIsRewardedSupported = function() {
    return bridge.advertisement.isRewardedSupported.toString()
}

window.getRewardedPlacement = function() {
    if (bridge.advertisement.rewardedPlacement) {
        return bridge.advertisement.rewardedPlacement
    } else {
        return ''
    }
}

window.showBanner = function(position, placement) {
    bridge.advertisement.showBanner(position, placement)
}

window.hideBanner = function() {
    bridge.advertisement.hideBanner()
}

window.showInterstitial = function(placement) {
    bridge.advertisement.showInterstitial(placement)
}

window.showRewarded = function(placement) {
    bridge.advertisement.showRewarded(placement)
}

window.getIsAdvancedBannersSupported = function() {
    return bridge.advertisement.isAdvancedBannersSupported.toString()
}

window.getAdvancedBannersState = function() {
    if (bridge.advertisement.advancedBannersState) {
        return bridge.advertisement.advancedBannersState
    } else {
        return ''
    }
}

window.showAdvancedBanners = function(placement) {
    bridge.advertisement.showAdvancedBanners(placement)
}

window.hideAdvancedBanners = function() {
    bridge.advertisement.hideAdvancedBanners()
}

window.checkAdBlock = function() {
    bridge.advertisement.checkAdBlock()
        .then(result => {
            sendMessageToUnity('OnCheckAdBlockCompleted', result.toString())
        })
        .catch(error => {
            sendMessageToUnity('OnCheckAdBlockCompleted', 'false')
        })
}


// social
window.getIsShareSupported = function() {
    return bridge.social.isShareSupported.toString()
}

window.getIsInviteFriendsSupported = function() {
    return bridge.social.isInviteFriendsSupported.toString()
}

window.getIsJoinCommunitySupported = function() {
    return bridge.social.isJoinCommunitySupported.toString()
}

window.getIsCreatePostSupported = function() {
    return bridge.social.isCreatePostSupported.toString()
}

window.getIsAddToHomeScreenSupported = function() {
    return bridge.social.isAddToHomeScreenSupported.toString()
}

window.getIsAddToHomeScreenRewardSupported = function() {
    return bridge.social.isAddToHomeScreenRewardSupported.toString()
}

window.getIsAddToFavoritesSupported = function() {
    return bridge.social.isAddToFavoritesSupported.toString()
}

window.getIsAddToFavoritesRewardSupported = function() {
    return bridge.social.isAddToFavoritesRewardSupported.toString()
}

window.getIsRateSupported = function() {
    return bridge.social.isRateSupported.toString()
}

window.getIsExternalLinksAllowed = function() {
    return bridge.social.isExternalLinksAllowed.toString()
}

window.share = function(options) {
    if (options) {
        options = JSON.parse(options)
    }

    bridge.social.share(options)
        .then(() => {
            sendMessageToUnity('OnShareCompleted', 'true')
        })
        .catch(error => {
            sendMessageToUnity('OnShareCompleted', 'false')
        })
}

window.inviteFriends = function(options) {
    if (options) {
        options = JSON.parse(options)
    }

    bridge.social.inviteFriends(options)
        .then(() => {
            sendMessageToUnity('OnInviteFriendsCompleted', 'true')
        })
        .catch(error => {
            sendMessageToUnity('OnInviteFriendsCompleted', 'false')
        })
}

window.joinCommunity = function(options) {
    if (options) {
        options = JSON.parse(options)
    }

    bridge.social.joinCommunity(options)
        .then(() => {
            sendMessageToUnity('OnJoinCommunityCompleted', 'true')
        })
        .catch(error => {
            sendMessageToUnity('OnJoinCommunityCompleted', 'false')
        })
}

window.createPost = function(options) {
    if (options) {
        options = JSON.parse(options)
    }

    bridge.social.createPost(options)
        .then(() => {
            sendMessageToUnity('OnCreatePostCompleted', 'true')
        })
        .catch(error => {
            sendMessageToUnity('OnCreatePostCompleted', 'false')
        })
}

window.addToHomeScreen = function() {
    bridge.social.addToHomeScreen()
        .then(() => {
            sendMessageToUnity('OnAddToHomeScreenCompleted', 'true')
        })
        .catch(error => {
            sendMessageToUnity('OnAddToHomeScreenCompleted', 'false')
        })
}

window.addToFavorites = function() {
    bridge.social.addToFavorites()
        .then(() => {
            sendMessageToUnity('OnAddToFavoritesCompleted', 'true')
        })
        .catch(error => {
            sendMessageToUnity('OnAddToFavoritesCompleted', 'false')
        })
}

window.rate = function() {
    bridge.social.rate()
        .then(() => {
            sendMessageToUnity('OnRateCompleted', 'true')
        })
        .catch(error => {
            sendMessageToUnity('OnRateCompleted', 'false')
        })
}

window.getAddToHomeScreenReward = function() {
    bridge.social.getAddToHomeScreenReward()
        .then(() => {
            sendMessageToUnity('OnGetAddToHomeScreenRewardCompleted', 'true')
        })
        .catch(error => {
            sendMessageToUnity('OnGetAddToHomeScreenRewardCompleted', 'false')
        })
}

window.getAddToFavoritesReward = function() {
    bridge.social.getAddToFavoritesReward()
        .then(() => {
            sendMessageToUnity('OnGetAddToFavoritesRewardCompleted', 'true')
        })
        .catch(error => {
            sendMessageToUnity('OnGetAddToFavoritesRewardCompleted', 'false')
        })
}


// leaderboards
window.getLeaderboardsType = function() {
    return bridge.leaderboards.type
}

window.leaderboardsSetScore = function(id, score) {
    score = parseInt(score)
    bridge.leaderboards.setScore(id, score)
        .then(() => {
            sendMessageToUnity('OnLeaderboardsSetScoreCompleted', 'true')
        })
        .catch(error => {
            sendMessageToUnity('OnLeaderboardsSetScoreCompleted', 'false')
        })
}

window.leaderboardsGetEntries = function(id) {
    bridge.leaderboards.getEntries(id)
        .then(data => {
            if (data) {
                sendMessageToUnity('OnLeaderboardsGetEntriesCompletedSuccess', JSON.stringify(data))
            } else {
                sendMessageToUnity('OnLeaderboardsGetEntriesCompletedSuccess', '')
            }
        })
        .catch(error => {
            sendMessageToUnity('OnLeaderboardsGetEntriesCompletedFailed', 'false')
        })
}

window.leaderboardsShowNativePopup = function(id) {
    bridge.leaderboards.showNativePopup(id)
        .then(() => {
            sendMessageToUnity('OnLeaderboardsShowNativePopupCompleted', 'true')
        })
        .catch(error => {
            sendMessageToUnity('OnLeaderboardsShowNativePopupCompleted', 'false')
        })
}

window.getIsPaymentsSupported = function() {
    return bridge.payments.isSupported.toString()
}

window.paymentsPurchase = function(id, options) {
    if (options) {
        options = JSON.parse(options)
    }

    bridge.payments.purchase(id, options)
        .then(data => {
            if (data) {
                if (typeof data !== 'string') {
                    data = JSON.stringify(data)
                }

                sendMessageToUnity('OnPaymentsPurchaseCompleted', data)
            } else {
                sendMessageToUnity('OnPaymentsPurchaseCompleted', '')
            }
        })
        .catch(error => {
            sendMessageToUnity('OnPaymentsPurchaseFailed', '')
        })
}

window.paymentsConsumePurchase = function(id) {
    bridge.payments.consumePurchase(id)
        .then(data => {
            if (data) {
                if (typeof data !== 'string') {
                    data = JSON.stringify(data)
                }

                sendMessageToUnity('OnPaymentsConsumePurchaseCompleted', data)
            } else {
                sendMessageToUnity('OnPaymentsConsumePurchaseCompleted', '')
            }
        })
        .catch(error => {
            sendMessageToUnity('OnPaymentsConsumePurchaseFailed', '')
        })
}

window.paymentsGetCatalog = function() {
    bridge.payments.getCatalog()
        .then(data => {
            if (data) {
                if (typeof data !== 'string') {
                    data = JSON.stringify(data)
                }

                sendMessageToUnity('OnPaymentsGetCatalogCompletedSuccess', data)
            } else {
                sendMessageToUnity('OnPaymentsGetCatalogCompletedSuccess', '')
            }
        })
        .catch(error => {
            sendMessageToUnity('OnPaymentsGetCatalogCompletedFailed', '')
        })
}

window.paymentsGetPurchases = function() {
    bridge.payments.getPurchases()
        .then(data => {
            if (data) {
                if (typeof data !== 'string') {
                    data = JSON.stringify(data)
                }

                sendMessageToUnity('OnPaymentsGetPurchasesCompletedSuccess', data)
            } else {
                sendMessageToUnity('OnPaymentsGetPurchasesCompletedSuccess', '')
            }
        })
        .catch(error => {
            sendMessageToUnity('OnPaymentsGetPurchasesCompletedFailed', '')
        })
}

window.getIsRemoteConfigSupported = function() {
    return bridge.remoteConfig.isSupported.toString()
}

window.remoteConfigGet = function(options) {
    if (options) {
        options = JSON.parse(options)
    }

    bridge.remoteConfig.get(options)
        .then(data => {
            if (typeof data !== 'string') {
                data = JSON.stringify(data)
            }

            sendMessageToUnity('OnRemoteConfigGetSuccess', data)
        })
        .catch(error => {
            sendMessageToUnity('OnRemoteConfigGetFailed', '')
        })
}

window.getIsAchievementsSupported = function() {
    return bridge.achievements.isSupported.toString()
}

window.getIsGetAchievementsListSupported = function() {
    return bridge.achievements.isGetListSupported.toString()
}

window.getIsAchievementsNativePopupSupported = function() {
    return bridge.achievements.isNativePopupSupported.toString()
}

window.achievementsUnlock = function(options) {
    if (options) {
        options = JSON.parse(options)
    }

    bridge.achievements.unlock(options)
        .then(() => {
            sendMessageToUnity('OnAchievementsUnlockCompleted', 'true')
        })
        .catch(error => {
            sendMessageToUnity('OnAchievementsUnlockCompleted', 'false')
        })
}

window.achievementsShowNativePopup = function(options) {
    if (options) {
        options = JSON.parse(options)
    }

    bridge.achievements.showNativePopup(options)
        .then(() => {
            sendMessageToUnity('OnAchievementsShowNativePopupCompleted', 'true')
        })
        .catch(error => {
            sendMessageToUnity('OnAchievementsShowNativePopupCompleted', 'false')
        })
}

window.achievementsGetList = function(options) {
    if (options) {
        options = JSON.parse(options)
    }

    bridge.achievements.getList(options)
        .then(data => {
            if (data) {
                if (typeof data !== 'string') {
                    data = JSON.stringify(data)
                }

                sendMessageToUnity('OnAchievementsGetListCompletedSuccess', data)
            } else {
                sendMessageToUnity('OnAchievementsGetListCompletedSuccess', '')
            }
        })
        .catch(error => {
            sendMessageToUnity('OnAchievementsGetListCompletedFailed', 'false')
        })
}
