import { cp, mkdir, readdir, rm, stat, writeFile } from 'node:fs/promises';
import { existsSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, resolve } from 'node:path';
import { listFileViewerRendererAssetManifests } from '@file-viewer/core/assets';
const distDir = dirname(fileURLToPath(import.meta.url));
const packageDir = resolve(distDir, '..');
export const DEFAULT_VIEWER_PUBLIC_DIR = 'public/file-viewer';
export const DEFAULT_VIEWER_ASSET_BASE_URL = '/file-viewer/';
export const VIEWER_ASSET_MANIFEST_FILENAME = 'flyfish-viewer-assets.json';
export const getViewerAssetDir = () => resolve(packageDir, 'viewer');
export const getDefaultViewerTargetDir = () => {
    return resolve(process.env.INIT_CWD || process.cwd(), DEFAULT_VIEWER_PUBLIC_DIR);
};
const removeMacMetadata = async (dir) => {
    const entries = await readdir(dir, { withFileTypes: true });
    await Promise.all(entries.map(entry => {
        const path = resolve(dir, entry.name);
        if (entry.name === '.DS_Store') {
            return rm(path, { force: true });
        }
        if (entry.isDirectory()) {
            return removeMacMetadata(path);
        }
        return undefined;
    }));
};
const isExpectedAssetKind = (asset, pathStat) => {
    return asset.kind === 'wasm-directory' ? pathStat.isDirectory() : pathStat.isFile();
};
export const validateViewerAssets = async (options = {}) => {
    const sourceDir = resolve(options.sourceDir || getViewerAssetDir());
    const assets = await Promise.all(listFileViewerRendererAssetManifests()
        .flatMap(manifest => manifest.assets)
        .filter(asset => asset.target === 'public' && asset.defaultPath)
        .map(async (asset) => {
        const relativePath = asset.defaultPath || '';
        const absolutePath = resolve(sourceDir, relativePath);
        let exists = false;
        try {
            exists = isExpectedAssetKind(asset, await stat(absolutePath));
        }
        catch {
            exists = false;
        }
        return {
            id: asset.id,
            rendererId: asset.rendererId,
            kind: asset.kind,
            target: asset.target,
            required: asset.required,
            relativePath,
            absolutePath,
            exists,
            description: asset.description
        };
    }));
    const missingRequired = assets.filter(asset => asset.required && !asset.exists);
    const missingOptional = assets.filter(asset => !asset.required && !asset.exists);
    return {
        sourceDir,
        valid: missingRequired.length === 0,
        checkedAt: new Date().toISOString(),
        assets,
        missingRequired,
        missingOptional
    };
};
const toViewerAssetManifestValidationItem = (item) => {
    const { absolutePath: _absolutePath, ...manifestItem } = item;
    return manifestItem;
};
export const toViewerAssetManifestValidation = (validation) => {
    return {
        valid: validation.valid,
        checkedAt: validation.checkedAt,
        assets: validation.assets.map(toViewerAssetManifestValidationItem),
        missingRequired: validation.missingRequired.map(toViewerAssetManifestValidationItem),
        missingOptional: validation.missingOptional.map(toViewerAssetManifestValidationItem)
    };
};
export const buildViewerAssetManifest = (validation) => {
    return {
        schemaVersion: 1,
        generatedAt: new Date().toISOString(),
        rendererAssetManifests: listFileViewerRendererAssetManifests(),
        validation: toViewerAssetManifestValidation(validation)
    };
};
export const writeViewerAssetManifest = async (targetDir, manifest) => {
    const assetManifestPath = resolve(targetDir, VIEWER_ASSET_MANIFEST_FILENAME);
    await writeFile(assetManifestPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
    return assetManifestPath;
};
export const copyViewerAssets = async (options = {}) => {
    const sourceDir = resolve(options.sourceDir || getViewerAssetDir());
    const targetDir = resolve(options.targetDir || getDefaultViewerTargetDir());
    if (!existsSync(sourceDir)) {
        throw new Error(`Missing viewer asset output: ${sourceDir}`);
    }
    if (options.clean !== false) {
        await rm(targetDir, { force: true, recursive: true });
    }
    await mkdir(targetDir, { recursive: true });
    await cp(sourceDir, targetDir, { recursive: true });
    await removeMacMetadata(targetDir);
    const validation = await validateViewerAssets({ sourceDir: targetDir });
    const assetManifestPath = await writeViewerAssetManifest(targetDir, buildViewerAssetManifest(validation));
    if (!validation.valid) {
        const missing = validation.missingRequired
            .map(asset => `${asset.rendererId}:${asset.relativePath}`)
            .join(', ');
        throw new Error(`Viewer static assets are missing required resources: ${missing}`);
    }
    return {
        sourceDir,
        targetDir,
        assetBaseUrl: DEFAULT_VIEWER_ASSET_BASE_URL,
        assetManifestPath,
        validation
    };
};
