window.router = new class {
    get csrf() {
        return u("meta[name=csrf]").attr("value")
    }

    __isScriptAlreadyLoaded(script) {
        if(script.src) {
            const script_url = new URL(script.src)
            const script_main_part = script_url.pathname

            return u(`script[src^='${script_main_part}']`).length > 0
        }

        return false
    }

    __appendScript(script) {
        const _t_scr = document.createElement('script')
        _t_scr.crossorigin = 'anonymous'
        if(script.getAttribute('integrity')) {
            _t_scr.setAttribute('integrity', script.getAttribute('integrity'))
        }

        if(script.getAttribute('id')) { 
            _t_scr.id = script.id
        }

        if(script.getAttribute('type')) { 
            _t_scr.type = script.type
        }

        //const parent = script.parentNode
        //const idx = Array.from(parent.children).indexOf(script)

        if(script.src) {
            _t_scr.src = script.src
        } else {
            _t_scr.async = false
            _t_scr.textContent = script.textContent
        }   

        //parent.children[idx].before(script)
        document.body.appendChild(_t_scr)
    }

    __clearScripts() {
        u(`script:not([src])`).remove()
    }

    __closeMsgs() {
        window.messagebox_stack.forEach(msg => {
            if(msg.hidden) {
                return
            }

            msg.close()
        })
    }

    __appendPage(parsed_content) {
        const scripts_to_append = []
        const page_body = u(parsed_content.querySelector('.page_body'))
        const sidebar = u(parsed_content.querySelector('.sidebar'))
        const page_header = u(parsed_content.querySelector('.page_header'))
        const page_footer = u(parsed_content.querySelector('.page_footer'))
        const backdrop = u(parsed_content.querySelector('#backdrop'))
        if(page_body.length < 1) {
            throw new Error('Invalid page has been loaded')
            return
        }

        window.__current_page_audio_context = null
        this.__clearScripts()
        parsed_content.querySelectorAll('.page_body script, #_js_ep_script').forEach(script => {
            if(!this.__isScriptAlreadyLoaded(script)) {
                scripts_to_append.push(script)
                script.parentNode.removeChild(script)
            }
        })
        u('.page_body').html(page_body.html())
        u('.sidebar').html(sidebar.html())
        u('.page_footer').html(page_footer.html())
        if(backdrop.length > 0) {
            if(u('#backdrop').length == 0) {
                u('body').append(`<div id="backdrop"></div>`)
            }
            u('#backdrop').nodes[0].outerHTML = (backdrop.nodes[0].outerHTML)
        } else {
            u('#backdrop').remove()
        }
        
        if(u('.page_header #search_box select').length > 0 && page_header.find('#search_box select').length > 0) {
            u('.page_header #search_box select').nodes[0].value = page_header.find('#search_box select').nodes[0].value
        }

        if(u('.page_header #search_box input').length > 0 && page_header.find('#search_box input').length > 0) {
            u('.page_header #search_box input').nodes[0].value = page_header.find('#search_box input').nodes[0].value
        }

        if(page_header.hasClass('search_expanded_at_all')) {
            u('.page_header').addClass('search_expanded_at_all').addClass('search_expanded')
        } else {
            if(u('.page_header').hasClass('search_expanded_at_all')) {
                u('.page_header').removeClass('search_expanded_at_all').removeClass('search_expanded')
            } else {
                u('.page_header').removeClass('search_expanded')
            }
        }
        
        u("meta[name=csrf]").attr("value", u(parsed_content.querySelector('meta[name=csrf]')).attr('value'))
        
        document.title = parsed_content.title
        scripts_to_append.forEach(append_me => {
            this.__appendScript(append_me)
        })
    }

    async __integratePage(scrolling = null) {
        window.temp_y_scroll = null
        u('.toTop').removeClass('has_down')
        window.scrollTo(0, scrolling ?? 0)
        bsdnHydrate()

        if(u('.paginator:not(.paginator-at-top)').length > 0) {
            showMoreObserver.observe(u('.paginator:not(.paginator-at-top)').nodes[0])
        }

        if(u(`div[class$="_small_block"]`).length > 0 && typeof smallBlockObserver != 'undefined') {
            smallBlockObserver.observe(u(`div[class$="_small_block"]`).nodes[0])
        }

        if(window.player) {
            window.player.dump()
            await window.player._handlePageTransition()
        }
    }

    __unlinkObservers() {
        if(u('.paginator:not(.paginator-at-top)').length > 0) {
            showMoreObserver.unobserve(u('.paginator:not(.paginator-at-top)').nodes[0])
        }

        if(u(`div[class$="_small_block"]`).length > 0 && typeof smallBlockObserver != 'undefined') {
            smallBlockObserver.unobserve(u(`div[class$="_small_block"]`).nodes[0])
        }
    }

    checkUrl(url) {
        if(window.openvk.disable_ajax == 1) {
            return false
        }

        if((localStorage.getItem('ux.disable_ajax_routing') ?? 0) == 1 || window.openvk.current_id == 0) {
            return false
        }

        if(!url || url == '') {
            return false
        }

        if(url.indexOf(location.origin) == -1) {
            return false
        }

        if(url.indexOf('hash=') != -1) {
            return false
        }

        if(url.indexOf('#close') != -1) {
            return false
        }

        return true
    }

    savePreviousPage() {
        this.prev_page_html = {
            url: location.href,
            pathname: location.pathname,
            html: u('.page_body').html(),
        }
    }

    async route(params = {}) {
        if(typeof params == 'string') {
            params = {
                url: params
            }
        }

        const old_url = location.href
        let url = params.url
        if(url.indexOf(location.origin)) {
            url = location.origin + url
        }

        if((localStorage.getItem('ux.disable_ajax_routing') ?? 0) == 1 || window.openvk.current_id == 0) {
            window.location.assign(url)
            return
        }

        if(this.prev_page_html && this.prev_page_html.pathname != location.pathname) {
            this.prev_page_html = null
        }
        
        const push_url = params.push_state ?? true
        const next_page_url = new URL(url)
        if(push_url) {
            history.pushState({'from_router': 1}, '', url)
        } else {
            history.replaceState({'from_router': 1}, '', url)
        }

        const parser = new DOMParser
        const next_page_request = await fetch(next_page_url, {
            method: 'AJAX',
            referrer: old_url,
            headers: {
                'X-OpenVK-Ajax-Query': '1',
            }
        })
        const next_page_text = await next_page_request.text()
        const parsed_content = parser.parseFromString(next_page_text, 'text/html')
        if(next_page_request.redirected) {
            history.replaceState({'from_router': 1}, '', next_page_request.url)
        }
        
        this.__closeMsgs()
        this.__unlinkObservers()

        try {
            this.__appendPage(parsed_content)
            await this.__integratePage()
        } catch(e) {
            console.error(e)
            next_page_url.searchParams.delete('al', 1)
            location.assign(next_page_url)
        }
    }
}

u(document).on('click', 'a', async (e) => {
    if(e.defaultPrevented) {
        console.log('AJAX | Skipping because default is prevented')
        return
    }
    
    const target = u(e.target).closest('a')
    const dom_url = target.attr('href')
    const id = target.attr('id')
    let url = target.nodes[0].href

    if(id) {
        if(['act_tab_a', 'ki', 'used', '_pinGroup', 'profile_link', 'minilink-friends', 'minilink-albums', 'minilink-messenger', 'minilink-groups', 'minilink-notifications'].indexOf(id) == -1) {
            console.log('AJAX | Skipping cuz maybe its function call link.')
            return
        }
    }

    /*if(url.indexOf('hash=') != -1) {
        e.preventDefault()
        return false
    }*/

    if(target.attr('rel') == 'nofollow') {
        console.log('AJAX | Skipped because its nofollow')
        return
    }

    if(target.nodes[0].hasAttribute('download')) {
        console.log('AJAX | Skipped because its download')
        return
    }

    if(!dom_url || dom_url == '#' || dom_url.indexOf('javascript:') != -1) {
        console.log('AJAX | Skipped because its anchor or function call')
        return
    }

    if(target.attr('target') == '_blank') {
        console.log('AJAX | Skipping because its _blank.')
        return
    }

    if(!window.router.checkUrl(url)) {
        return
    }

    // temporary fix
    if(dom_url == '/') {
        url = url + 'id0'
    }

    e.preventDefault()

    console.log(`AJAX | Going to URL ${url}`)
    await window.router.route({
        url: url,
    })
})

u(document).on('submit', 'form', async (e) => {
    if(e.defaultPrevented) {
        return
    }
  
    if(u('#ajloader').hasClass('shown')) {
        e.preventDefault()
        return
    }

    if((localStorage.getItem('ux.disable_ajax_routing') ?? 0) == 1 || window.openvk.current_id == 0) {
        return false
    }

    if(window.openvk.disable_ajax == 1) {
        return false
    }

    if(e.target.closest('#write')) {
        const target = u(e.target)
        collect_attachments_node(target)
    }

    u('#ajloader').addClass('shown')

    const form = e.target
    const method = form.method ?? 'get'
    const url = form.action
    if(form.onsubmit || url.indexOf('/settings?act=interface') != -1) {
        u('#ajloader').removeClass('shown')
        return false
    }
    e.preventDefault()

    const url_object = new URL(url)
    if(method == 'get' || method == 'GET') {
        //url_object.searchParams.append('hash', window.router.csrf)
        $(form).serializeArray().forEach(param => {
            url_object.searchParams.append(param.name, param.value)
        })
    }

    if(!url) {
        u('#ajloader').removeClass('shown')
        return
    }

    const form_data = serializeForm(form, e.submitter)
    const request_object = {
        method: method,
        headers: {
            'X-OpenVK-Ajax-Query': '1',
        }
    }

    if(method != 'GET' && method != 'get') {
        request_object.body = form_data
    }

    const form_res = await fetch(url_object, request_object)
    const form_result = await form_res.text()
    switch(form_res.status) {
        case 500:
        case 502:
            makeError(form_res.statusText)
            break
    }

    const parser = new DOMParser
    const parsed_content = parser.parseFromString(form_result, 'text/html')

    if(form_res.redirected) {
        history.replaceState({'from_router': 1}, '', form_res.url)
    } else {
        const __new_url = new URL(form_res.url)
        __new_url.searchParams.delete('al')
        __new_url.searchParams.delete('hash')

        history.pushState({'from_router': 1}, '', __new_url)
    }
    
    window.router.__appendPage(parsed_content)
    window.router.__closeMsgs()
    await window.router.__integratePage()

    u('#ajloader').removeClass('shown')
})

window.addEventListener('popstate', (e) => {
    e.preventDefault();
    /*if(window.router.prev_page_html) {
        u('.page_body').html(window.router.prev_page_html.html)
        history.replaceState({'from_router': 1}, '', window.router.prev_page_html.url)
        window.router.prev_page_html = null
        window.router.__integratePage()
        return
    }*/

    window.router.route({
        url: location.href,
        push_state: false,
    })
})
