import { writeFile } from 'fs';
import { tryParseNeedleEngineSrcAttributeFromHtml } from '../common/needle-engine.js';



/**
 * @param {'serve' | 'build'} command
 * @param {{} | undefined | null} config
 * @param {import('../types').userSettings} userSettings
 * @returns {import('vite').Plugin[] | null}
 */
export const needleApp = (command, config, userSettings) => {

    if (command !== "build") {
        return null;
    }

    /** @type {Array<import("rollup").OutputChunk>} */
    const entryFiles = new Array();

    let outputDir = "dist";

    /**
     * @type {import('vite').Plugin}
     */
    return [
        {
            name: 'needle:app',
            enforce: "post",
            configResolved(config) {
                outputDir = config.build.outDir || "dist";
            },
            transformIndexHtml: {
                handler: async function (html, context) {
                    const name = context.filename;
                    if (name.includes("index.html")) {
                        if (context.chunk?.isEntry) {
                            try {
                                entryFiles.push(context.chunk);
                                const path = context.chunk.fileName;
                                // console.log("[needle-dependencies] entry chunk imports", {
                                //     name: context.chunk.fileName,
                                //     imports: context.chunk.imports,
                                //     dynamicImports: context.chunk.dynamicImports,
                                //     refs: context.chunk.referencedFiles,
                                // });

                                const referencedGlbs = tryParseNeedleEngineSrcAttributeFromHtml(html);
                                const webComponent = generateNeedleEmbedWebComponent(path, referencedGlbs);
                                await writeFile(`${outputDir}/needle-app.js`, webComponent, (err) => {
                                    if (err) {
                                        console.error("[needle-app] could not create needle-app.js", err);
                                    }
                                    else {
                                        console.log("[needle-app] created needle-app.js");
                                    }
                                });
                            }
                            catch (e) {
                                console.warn("WARN: could not create needle-app.js\n", e);
                            }
                        }
                    }
                }
            },

        }
    ]
}


/**
 * @param {string} filepath
 * @param {string[]} needleEngineSrcPaths
 * @returns {string}
 */
function generateNeedleEmbedWebComponent(filepath, needleEngineSrcPaths) {


    // filepath is e.g. `assets/index-XXXXXXXX.js`
    // we want to make sure the path is correct relative to where the component will be used
    // this script will be emitted in the output directory root (e.g. needle-embed.js)

    const src = needleEngineSrcPaths?.length ? `${needleEngineSrcPaths[0]}` : "";

    const componentName = 'needle-app';
    const className = 'NeedleApp';

    return `
class ${className} extends HTMLElement {
    constructor() {
        super();
        this.attachShadow({ mode: 'open' });
        const template = document.createElement('template');
        template.innerHTML = \`
            <style>
                :host {
                    position: relative;
                    display: block;
                    width: 100%;
                    height: 100%;
                    margin: 0;
                    padding: 0;
                }
                needle-engine {
                    position: absolute;
                    top: 0;
                    left: 0;
                    width: 100%;
                    height: 100%;
                }
            </style>
        \`;
        this.shadowRoot.appendChild(template.content.cloneNode(true));

        const script = document.createElement('script');
        script.type = 'module';
        const url = new URL('.', import.meta.url);
        let basePath = this.getAttribute('base-path') || \`\${url.protocol}//\${url.host}\${url.pathname}\`;
        while(basePath.endsWith('/')) {
            basePath = basePath.slice(0, -1);
        }
        script.src = this.getAttribute('script-src') || \`\${basePath}/${filepath}\`;
        this.shadowRoot.appendChild(script);

        const needleEngine = document.createElement('needle-engine');
        needleEngine.src = this.getAttribute('src') || ${src?.length ? `\${basePath}/${needleEngineSrcPaths}` : undefined};
        this.shadowRoot.appendChild(needleEngine);

        console.debug(basePath, script.src, needleEngine.getAttribute("src"));
    }

    onConnectedCallback() {
        console.debug('NeedleEmbed connected to the DOM');
    }

    disconnectedCallback() {
        console.debug('NeedleEmbed disconnected from the DOM');
    }
}


if (!customElements.get('${componentName}')) {
    console.debug("Defining ${componentName}");
    customElements.define('${componentName}', ${className});
}
`
}