import * as i0 from '@angular/core';
import { inject, Injectable } from '@angular/core';
import { I18nService } from '@sdcorejs/angular/i18n';
import { OpenFile, PreopenDirectory, File as File$1, ConsoleStdout, WASI } from '@bjorn3/browser_wasi_shim';
import * as i1 from '@sdcorejs/angular/services/notify';
import * as i2 from '@sdcorejs/angular/services/loading';

/* Pandoc WASM core logic — adapted from pandoc-wasm/src/core.js
 *
 * This file is a local copy of the environment-agnostic pandoc core.
 * It imports @bjorn3/browser_wasi_shim directly, avoiding the pandoc-wasm
 * package entry points which use top-level await (incompatible with
 * Angular's esbuild/Vite build pipeline).
 *
 * Source: https://github.com/pandoc/pandoc-wasm (GPL-2.0-or-later)
 */
// @ts-nocheck
function createPandocInstance(wasmBinary) {
    const args = ['pandoc.wasm', '+RTS', '-H64m', '-RTS'];
    const env = [];
    const fileSystem = new Map();
    const fds = [
        new OpenFile(new File$1(new Uint8Array(), { readonly: true })),
        ConsoleStdout.lineBuffered((msg) => console.log(`[WASI stdout] ${msg}`)),
        ConsoleStdout.lineBuffered((msg) => console.warn(`[WASI stderr] ${msg}`)),
        new PreopenDirectory('/', fileSystem),
    ];
    const options = { debug: false };
    const wasi = new WASI(args, env, fds, options);
    return WebAssembly.instantiate(wasmBinary, {
        wasi_snapshot_preview1: wasi.wasiImport,
    }).then(({ instance }) => {
        wasi.initialize(instance);
        instance.exports.__wasm_call_ctors();
        function memory_data_view() {
            return new DataView(instance.exports.memory.buffer);
        }
        const argc_ptr = instance.exports.malloc(4);
        memory_data_view().setUint32(argc_ptr, args.length, true);
        const argv = instance.exports.malloc(4 * (args.length + 1));
        for (let i = 0; i < args.length; ++i) {
            const arg = instance.exports.malloc(args[i].length + 1);
            new TextEncoder().encodeInto(args[i], new Uint8Array(instance.exports.memory.buffer, arg, args[i].length));
            memory_data_view().setUint8(arg + args[i].length, 0);
            memory_data_view().setUint32(argv + 4 * i, arg, true);
        }
        memory_data_view().setUint32(argv + 4 * args.length, 0, true);
        const argv_ptr = instance.exports.malloc(4);
        memory_data_view().setUint32(argv_ptr, argv, true);
        instance.exports.hs_init_with_rtsopts(argc_ptr, argv_ptr);
        async function addFile(filename, data, readonly) {
            let uint8Array;
            if (typeof data === 'string') {
                uint8Array = new TextEncoder().encode(data);
            }
            else {
                const buffer = await data.arrayBuffer();
                uint8Array = new Uint8Array(buffer);
            }
            const file = new File$1(uint8Array, { readonly });
            fileSystem.set(filename, file);
        }
        async function convert(options, stdin, files) {
            const opts_str = JSON.stringify(options);
            const encoded = new TextEncoder().encode(opts_str);
            const opts_ptr = instance.exports.malloc(encoded.length);
            new TextEncoder().encodeInto(opts_str, new Uint8Array(instance.exports.memory.buffer, opts_ptr, encoded.length));
            files = { ...files };
            fileSystem.clear();
            const in_file = new File$1(new Uint8Array(), { readonly: true });
            const out_file = new File$1(new Uint8Array(), { readonly: false });
            const err_file = new File$1(new Uint8Array(), { readonly: false });
            const warnings_file = new File$1(new Uint8Array(), { readonly: false });
            fileSystem.set('stdin', in_file);
            fileSystem.set('stdout', out_file);
            fileSystem.set('stderr', err_file);
            fileSystem.set('warnings', warnings_file);
            const knownFiles = new Set(['stdin', 'stdout', 'stderr', 'warnings']);
            for (const filename in files) {
                await addFile(filename, files[filename], true);
                knownFiles.add(filename);
            }
            const outputFileName = options['output-file'] || null;
            const extractMediaPath = options['extract-media'] || null;
            if (outputFileName) {
                await addFile(outputFileName, new Blob(), false);
                knownFiles.add(outputFileName);
            }
            if (extractMediaPath) {
                await addFile(extractMediaPath, new Blob(), false);
                if (extractMediaPath.endsWith('.zip')) {
                    knownFiles.add(extractMediaPath);
                }
            }
            if (stdin) {
                in_file.data = new TextEncoder().encode(stdin);
            }
            instance.exports.convert(opts_ptr, encoded.length);
            if (options['output-file']) {
                const outputFile = fileSystem.get(options['output-file']);
                if (outputFile && outputFile.data && outputFile.data.length > 0) {
                    files[options['output-file']] = new Blob([outputFile.data]);
                }
            }
            if (options['extract-media']) {
                const mediaFile = fileSystem.get(options['extract-media']);
                if (mediaFile && mediaFile.data && mediaFile.data.length > 0) {
                    files[options['extract-media']] = new Blob([mediaFile.data], { type: 'application/zip' });
                }
            }
            const mediaFiles = {};
            for (const [name, fileData] of fileSystem.entries()) {
                if (!knownFiles.has(name) && fileData && fileData.data && fileData.data.length > 0) {
                    const blob = new Blob([fileData.data]);
                    files[name] = blob;
                    if (name !== outputFileName && name !== extractMediaPath) {
                        mediaFiles[name] = blob;
                    }
                }
            }
            const rawWarnings = new TextDecoder('utf-8', { fatal: true }).decode(warnings_file.data);
            let warnings = [];
            if (rawWarnings) {
                try {
                    warnings = JSON.parse(rawWarnings);
                }
                catch (e) {
                    console.warn('Failed to parse warnings:', e);
                }
            }
            return {
                stdout: new TextDecoder('utf-8', { fatal: true }).decode(out_file.data),
                stderr: new TextDecoder('utf-8', { fatal: true }).decode(err_file.data),
                warnings,
                files,
                mediaFiles,
            };
        }
        return { convert };
    });
}

class SdDocxService {
    notifyService;
    loadingService;
    #i18n = inject(I18nService);
    #DEFAULT_MAX_SIZE_MB = 50;
    #VALID_EXTENSIONS = ['.doc', '.docx'];
    #PANDOC_WASM_URL = 'https://pandoc.github.io/pandoc-wasm/pandoc.wasm';
    #fileInput = null;
    #pandocInstance = null;
    constructor(notifyService, loadingService) {
        this.notifyService = notifyService;
        this.loadingService = loadingService;
    }
    async open(options) {
        return new Promise(resolve => {
            this.#createFileInput();
            if (!this.#fileInput) {
                resolve(null);
                return;
            }
            const handleChange = async (event) => {
                const input = event.target;
                const file = input.files?.[0];
                if (!file) {
                    resolve(null);
                    return;
                }
                this.loadingService.start();
                try {
                    const result = await this.convertToHtml(file, options);
                    resolve(result);
                }
                catch (error) {
                    console.error('[SdDocxService] DocX conversion error:', error);
                    this.notifyService.error(this.#i18n.t('core.docx.convert-error'));
                    resolve(null);
                }
                finally {
                    input.value = '';
                    input.removeEventListener('change', handleChange);
                    this.loadingService.stop();
                }
            };
            this.#fileInput.addEventListener('change', handleChange, { once: true });
            this.#fileInput.click();
        });
    }
    #createFileInput() {
        if (this.#fileInput) {
            return;
        }
        this.#fileInput = document.createElement('input');
        this.#fileInput.type = 'file';
        this.#fileInput.accept = '.doc,.docx';
        this.#fileInput.style.display = 'none';
        document.body.appendChild(this.#fileInput);
    }
    async #getPandocInstance() {
        if (this.#pandocInstance) {
            return this.#pandocInstance;
        }
        console.log('[SdDocxService] Fetching WASM binary from:', this.#PANDOC_WASM_URL);
        const wasmResponse = await fetch(this.#PANDOC_WASM_URL);
        if (!wasmResponse.ok) {
            throw new Error(`Failed to fetch pandoc.wasm: ${wasmResponse.status} ${wasmResponse.statusText}`);
        }
        console.log('[SdDocxService] WASM fetched, size:', wasmResponse.headers.get('content-length'));
        const wasmBinary = await wasmResponse.arrayBuffer();
        console.log('[SdDocxService] WASM binary loaded, bytes:', wasmBinary.byteLength);
        this.#pandocInstance = await createPandocInstance(wasmBinary);
        console.log('[SdDocxService] Pandoc instance created successfully');
        return this.#pandocInstance;
    }
    async convertToHtml(input, options) {
        const opts = {
            validateFormat: true,
            validateSize: true,
            maxSizeInMb: this.#DEFAULT_MAX_SIZE_MB,
            ...options,
        };
        try {
            let fileName;
            let fileSize;
            let blob;
            if (input instanceof File) {
                fileName = input.name;
                fileSize = input.size;
                blob = input;
            }
            else if (input instanceof Blob) {
                fileSize = input.size;
                blob = input;
            }
            else {
                blob = new Blob([input], {
                    type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
                });
            }
            if (opts.validateFormat && fileName) {
                if (!this.#isValidFormat(fileName)) {
                    this.notifyService.error(this.#i18n.t('core.docx.invalid-format'));
                    return null;
                }
            }
            if (opts.validateSize && fileSize !== undefined) {
                const maxSizeInBytes = opts.maxSizeInMb * 1024 * 1024;
                if (fileSize > maxSizeInBytes) {
                    this.notifyService.error(this.#i18n.t('core.docx.size-exceeded'));
                    return null;
                }
            }
            console.log('[SdDocxService] Getting pandoc instance...');
            const pandoc = await this.#getPandocInstance();
            console.log('[SdDocxService] Converting DOCX, blob size:', blob.size);
            const pandocOpts = {
                from: 'docx',
                to: 'html',
                'input-files': ['document.docx'],
                standalone: true,
                'embed-resources': true,
            };
            const result = await pandoc.convert(pandocOpts, null, { 'document.docx': blob });
            console.log('[SdDocxService] Conversion done, stdout length:', result.stdout?.length, 'stderr:', result.stderr);
            return {
                html: result.stdout,
                messages: result.warnings.map((w) => String(w)),
            };
        }
        catch (error) {
            console.error('[SdDocxService] DocX conversion error:', error);
            this.notifyService.error(this.#i18n.t('core.docx.convert-error'));
            return null;
        }
    }
    async convertToHtmlString(input, options) {
        const result = await this.convertToHtml(input, options);
        return result?.html ?? null;
    }
    #isValidFormat(fileName) {
        const lowerCaseName = fileName.toLowerCase();
        return this.#VALID_EXTENSIONS.some(ext => lowerCaseName.endsWith(ext));
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: SdDocxService, deps: [{ token: i1.SdNotifyService }, { token: i2.SdLoadingService }], target: i0.ɵɵFactoryTarget.Injectable });
    static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: SdDocxService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.24", ngImport: i0, type: SdDocxService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root',
                }]
        }], ctorParameters: () => [{ type: i1.SdNotifyService }, { type: i2.SdLoadingService }] });

/**
 * Generated bundle index. Do not edit.
 */

export { SdDocxService };
//# sourceMappingURL=sdcorejs-angular-services-docx.mjs.map
