import test from 'node:test';
import assert from 'node:assert/strict';

import { FileDownloader } from '../js/services/file-downloader.js';
import { FileViewer } from '../js/viewer/file-viewer.js';

class FakeElement {
    constructor(tagName = 'div') {
        this.tagName = tagName.toUpperCase();
        this.children = [];
        this.attributes = new Map();
        this.dataset = {};
        this.eventListeners = new Map();
        this.style = {};
        this.className = '';
        this.href = '';
        this.src = '';
        this.title = '';
        this.textContent = '';
        this.innerHTML = '';
        this.download = '';
    }

    append(...nodes) {
        this.children.push(...nodes);
    }

    appendChild(node) {
        this.children.push(node);
        return node;
    }

    prepend(node) {
        this.children.unshift(node);
        return node;
    }

    removeChild(node) {
        this.children = this.children.filter(child => child !== node);
        return node;
    }

    replaceChildren(...nodes) {
        this.children = [...nodes];
    }

    remove() {
        this.removed = true;
    }

    setAttribute(name, value) {
        this.attributes.set(name, String(value));
    }

    getAttribute(name) {
        return this.attributes.get(name);
    }

    removeAttribute(name) {
        this.attributes.delete(name);
    }

    addEventListener(type, handler) {
        this.eventListeners.set(type, handler);
    }

    click() {
        this.clicked = true;
    }
}

function installViewerDom(search) {
    const previous = {
        document: globalThis.document,
        window: globalThis.window,
        URL: globalThis.URL,
        fetch: globalThis.fetch,
        setTimeout: globalThis.setTimeout,
        consoleError: console.error,
        consoleWarn: console.warn,
    };
    const elements = {
        title: new FakeElement('h1'),
        type: new FakeElement('span'),
        download: new FakeElement('a'),
        content: new FakeElement('main'),
    };
    const body = new FakeElement('body');
    const created = [];

    globalThis.document = {
        title: '',
        body,
        getElementById(id) {
            return {
                'viewer-title': elements.title,
                'viewer-type': elements.type,
                'viewer-download': elements.download,
                'viewer-content': elements.content,
            }[id];
        },
        createElement(tagName) {
            const node = new FakeElement(tagName);
            created.push(node);
            return node;
        },
    };
    globalThis.window = {
        location: { search },
        open(url) {
            this.openedUrl = url;
        },
    };
    globalThis.URL = {
        createObjectURL() {
            return 'blob:tapops-download';
        },
        revokeObjectURL(url) {
            this.revokedUrl = url;
        },
    };
    globalThis.setTimeout = callback => {
        callback();
        return 1;
    };
    console.error = () => {};
    console.warn = () => {};

    return {
        elements,
        created,
        restore() {
            globalThis.document = previous.document;
            globalThis.window = previous.window;
            globalThis.URL = previous.URL;
            globalThis.fetch = previous.fetch;
            globalThis.setTimeout = previous.setTimeout;
            console.error = previous.consoleError;
            console.warn = previous.consoleWarn;
        },
    };
}

test('repository download fetches the Directus original-file URL', async (t) => {
    const { created, restore } = installViewerDom('');
    t.after(restore);

    let fetchedUrl = '';
    globalThis.fetch = async (url) => {
        fetchedUrl = url;
        return {
            ok: true,
            blob: async () => new Blob(['docx']),
        };
    };

    await FileDownloader.download('https://api.ifuntanhub.dev/assets/docx-id', 'Form KP.docx');

    const clickedAnchor = created.find(node => node.tagName === 'A' && node.clicked);
    assert.equal(fetchedUrl, 'https://api.ifuntanhub.dev/assets/docx-id?download');
    assert.equal(clickedAnchor.download, 'Form KP.docx');
});

test('DOCX preview renders Microsoft Office Online Viewer iframe', async (t) => {
    const { elements, restore } = installViewerDom('?id=docx-id&name=Form%20KP.docx&type=docx');
    t.after(restore);

    await new FileViewer().init();

    const iframe = elements.content.children[0];
    const assetUrl = 'https://api.ifuntanhub.dev/assets/docx-id';
    assert.equal(iframe.tagName, 'IFRAME');
    assert.equal(iframe.className, 'viewer-office-frame');
    assert.equal(iframe.src, `https://view.officeapps.live.com/op/embed.aspx?src=${encodeURIComponent(assetUrl)}`);
});

test('viewer download uses the Directus original-file URL', async (t) => {
    const { elements, created, restore } = installViewerDom('?id=pdf-id&name=Panduan.pdf&type=pdf');
    t.after(restore);

    let fetchedUrl = '';
    globalThis.fetch = async (url) => {
        fetchedUrl = url;
        return {
            ok: true,
            headers: { get: () => null },
            blob: async () => new Blob(['pdf']),
        };
    };

    await new FileViewer().init();
    await elements.download.eventListeners.get('click')({ preventDefault() {} });

    const clickedAnchor = created.find(node => node.tagName === 'A' && node.clicked);
    assert.equal(fetchedUrl, 'https://api.ifuntanhub.dev/assets/pdf-id?download');
    assert.equal(clickedAnchor.download, 'Panduan.pdf');
});
