import { fetchSource, getCompletePath } from '.';
import { IApp } from '../typings';
import { scopedCSS } from './scopedcss';
import { v4 } from 'uuid';
import { isRelativePath, isRemotezElement } from './tools';

// 请求link
function fetchLinkFormHtml (app:IApp, htmlDom: HTMLDivElement) {
    const head = htmlDom.querySelector('mustard-app-head');
    const linkEntries = Array.from(app.source.links.entries());
    // 通过fetch请求所有css资源
    const fetchLinkPromise:Promise<string>[] = [];
    for (const [url, info] of linkEntries) {
        fetchLinkPromise.push(
            info.isExternal ?
                fetchSource(url, app.url) :
                Promise.resolve(info.code)
        );
    }
    Promise.all(fetchLinkPromise).then(res =>{
        res.forEach(code => {
            const styleEle = document.createElement('style');
            styleEle.textContent = code;
            // 处理css，加上前缀 mustard-app[name='${appName}']
            scopedCSS(styleEle, app.name);
            head && head.appendChild(styleEle);
        });
        app.onLoad(htmlDom);
    }).catch(error => app.error(error));
}

function fetchScriptFormHtml (app:IApp, htmlDom: HTMLDivElement) {
    const scriptEntries = Array.from(app.source.scripts.entries());
    // 通过fetch请求所有css资源
    const fetchPromise:Promise<string>[] = [];
    for (const [url, info] of scriptEntries) {
        fetchPromise.push(
            info.isExternal ? 
                fetchSource(url, app.url) : 
                Promise.resolve(info.code));
    }
    Promise.all(fetchPromise).then(res =>{
        res.forEach((code, i) => {
            // 将代码放入缓存，再次渲染时可以从缓存中获取
            scriptEntries[i][1].code = code;
        });
        app.onLoad(htmlDom);
    }).catch(error => app.error(error));
}

/**
 * 递归并处理dom
 * 收集静态的样式和js
 * 处理远程资源 e.g img,video,audio
 * @param parent 
 * @param app 
 */
function extractSourceDom (parent:Element, app:IApp) {
    const children = Array.from(parent.children);

    children?.length && children.forEach(child => extractSourceDom(child, app));

    for (const dom of children) {
        // const attrs = dom.getAttributeNames();

        // attrs.forEach(attr => {
        //     // 处理dom上直接绑定的事件
        //     if(/^on[a-zA_Z]+/.test(attr)){
        //         const time = attr +  v4();
        //         app.source.domClick +=  `
        //             this.${time} = function(){
        //                 ${dom.getAttribute(attr)}}\n;
        //             `;               
        //         dom.setAttribute(attr,`proxyWindow.${time}()`);
        //     }
        // });
        
        // link 记录并收集，并提取src
        if(dom instanceof HTMLLinkElement) {
            const href = dom.getAttribute('href');
            if (dom.getAttribute('rel') === 'stylesheet' && href) {
                app.source.links.set(href, {
                    code: '',
                    isExternal: true
                });
            }
            parent.removeChild(dom);
        }else if(dom instanceof HTMLStyleElement) {
            // style 记录并收集，并提取code
            app.source.links.set(v4(), {
                code: dom.textContent ?? ''
            });
            parent.removeChild(dom);
        }else if(dom instanceof HTMLScriptElement) {
            // script 记录并收集，并提取code
            const src = dom.getAttribute('src');
            // 远程js
            if(src) {
                app.source.scripts.set(src, {
                    code: '',
                    isExternal: true // 是否远程js
                });
            }else{
                app.source.scripts.set(v4(), {
                    code: dom.textContent ?? ''
                });
            }
            parent.removeChild(dom);
        }else if(isRemotezElement(dom)) {
            // 远程资源相对地址处理
            const src = dom.getAttribute('src');
            if(isRelativePath(src)) {
                dom.setAttribute('src', getCompletePath(src, app.url));
            }
        }
    }
}

export function loadHtml (app:IApp) {
    fetchSource(app.url).then(html => {
        html = html
            .replace(/<head[^>]*>[\s\S]*?<\/head>/i, match =>
                match.replace(/<head/i, '<mustard-app-head').replace(/<\/head>/i, '</mustard-app-head>')
            ).replace(/<body[^>]*>[\s\S]*?<\/body>/i, match => 
                match.replace(/<body/i, '<mustard-app-body').replace(/<\/body>/i, '</mustard-app-body>')
            );

        // htmlText -> Dom
        const Box = document.createElement('div');
        Box.innerHTML = html;

        // 提取静态js和link，处理style
        extractSourceDom(Box, app);

        if(app.source.links.size) {
            fetchLinkFormHtml(app, Box);
        }else{
            app.onLoad(Box);
        }

        if(app.source.scripts.size) {
            fetchScriptFormHtml(app, Box);
        }else{
            app.onLoad(Box);
        }
    }).catch(error => app.error(error));
}