import { join } from 'node:path';
import { readFileSync } from 'node:fs';
import { getAllPackages } from './get-all-packages.js';
import { deslugify } from '@patternfly/pfe-tools/config.js';
const all = (...ps) => (x) => ps.every(p => p(x));
const not = (p) => (x) => !p(x);
const and = (p, q) => (x) => p(x) && q(x);
export const isField = (x) => x.kind === 'field';
export const isMethod = (x) => x.kind === 'method';
export const isStatic = (x) => !!x.static;
export const isPublic = (x) => !x.privacy || !x.privacy?.match?.(/private|protected/);
export const isPublicInstanceField = all(isField, not(isStatic), isPublic);
export const isPublicInstanceMethod = all(isMethod, not(isStatic), isPublic);
export const isCustomElement = (x) => 'tagName' in x;
export const isTheField = (x) => (y) => y.fieldName === x.name;
const readJsonSync = (path) => {
    try {
        return JSON.parse(readFileSync(path, 'utf8'));
    }
    catch {
        return null;
    }
};
class ManifestCustomElement {
    constructor(declaration, module, manifest) {
        this.declaration = declaration;
        this.module = module;
        this.manifest = manifest;
        const isAnAttr = (x) => !this.declaration?.attributes?.some?.(isTheField(x));
        this.tagName = this.declaration.tagName;
        this.attributes = this.declaration?.attributes ?? [];
        this.cssCustomProperties = this.declaration?.cssProperties ?? [];
        this.cssParts = this.declaration?.cssParts ?? [];
        this.description = this.declaration?.description ?? '';
        this.events = this.declaration?.events ?? [];
        this.methods = this.declaration?.members?.filter?.(isPublicInstanceMethod) ?? [];
        this.properties = this.declaration?.members?.filter?.(and(isPublicInstanceField, isAnAttr)) ?? [];
        this.slots = this.declaration?.slots ?? [];
        this.demos = this.declaration?.demos ?? [];
        this.summary = this.declaration?.summary ?? '';
        this.export = manifest.manifest
            ?.modules
            ?.flatMap(x => x.exports ?? [])
            ?.find(z => z.declaration.name === this.declaration.name);
    }
}
export class Manifest {
    constructor(manifest, packageJson, location) {
        this.manifest = manifest;
        this.packageJson = packageJson;
        this.location = location;
        this.declarations = new Map();
        /** file path to the custom elements manifest */
        this.path = '';
        if (manifest && packageJson && location && packageJson.customElements) {
            this.path = join(location, packageJson.customElements);
        }
        for (const mod of manifest?.modules ?? []) {
            for (const declaration of mod.declarations ?? []) {
                if (isCustomElement(declaration) && declaration.tagName) {
                    this.declarations.set(declaration.tagName, new ManifestCustomElement(declaration, mod, this));
                }
            }
        }
    }
    static #instances = new WeakMap();
    static empty() {
        return new Manifest(null, null);
    }
    static from({ package: packageJson, location }) {
        if (!Manifest.#instances.has(packageJson)) {
            const manifestPath = join(location, packageJson?.customElements ?? '');
            const json = readJsonSync(manifestPath);
            Manifest.#instances.set(packageJson, new Manifest(json, packageJson, location));
        }
        return Manifest.#instances.get(packageJson);
    }
    static getAll(rootDir = process.cwd()) {
        return getAllPackages(rootDir).flatMap(x => !x.package.customElements ? [] : [Manifest.from(x)]);
    }
    static { this.prettyTag = (tagName, aliases) => aliases?.[tagName] ?? tagName
        .replace(/^\w+-/, '')
        .toLowerCase()
        .replace(/(?:^|[-/\s])\w/g, x => x.toUpperCase())
        .replace(/-/g, ' '); }
    #tag(tagName) {
        return this.declarations?.get(tagName) ?? null;
    }
    /**
     */
    getTagNames() {
        return this.manifest?.modules
            ?.flatMap?.(m => m.exports
            ?.filter?.(x => x.kind === 'custom-element-definition')
            ?.map?.(x => x.name)) ?? [];
    }
    /**
     */
    getAttributes(tagName) {
        return this.#tag(tagName)?.attributes;
    }
    /**
     */
    getCssCustomProperties(tagName) {
        return this.#tag(tagName)?.cssCustomProperties;
    }
    /**
     */
    getCssParts(tagName) {
        return this.#tag(tagName)?.cssParts;
    }
    /**
     */
    getDescription(tagName) {
        return this.#tag(tagName)?.description;
    }
    /**
     */
    getEvents(tagName) {
        return this.#tag(tagName)?.events;
    }
    /**
     */
    getMethods(tagName) {
        return this.#tag(tagName)?.methods;
    }
    /**
     */
    getProperties(tagName) {
        return this.#tag(tagName)?.properties;
    }
    /**
     */
    getSummary(tagName) {
        return this.#tag(tagName)?.summary;
    }
    /**
     */
    getSlots(tagName) {
        return this.#tag(tagName)?.slots;
    }
    /**
     */
    getDemos(tagName) {
        return this.#tag(tagName)?.demos ?? [];
    }
    getAllDemos() {
        return this.manifest?.modules
            ?.flatMap?.(m => m.declarations)
            ?.filter?.((x) => !!x && isCustomElement(x))
            ?.flatMap?.(x => x?.demos ?? []) ?? [];
    }
    getDemoMetadata(tagName, options) {
        // eslint-disable-next-line @typescript-eslint/no-this-alias
        const manifest = this;
        const { prettyTag } = Manifest;
        return this.getDemos(tagName).map(demo => {
            const permalink = demo.url.replace(options.demoURLPrefix, '/');
            const [, slug = ''] = permalink.match(/\/components\/(.*)\/demo/) ?? [];
            const primaryElementName = deslugify(slug, options.rootDir);
            const filePath = demo.source?.href.replace(options.sourceControlURLPrefix, `${options.rootDir}/`) ?? '';
            const [last = ''] = filePath.split('/').reverse();
            const filename = last.replace('.html', '');
            const isMainElementDemo = this.getTagNames().includes(filename);
            const title = isMainElementDemo ? options.aliases[tagName] ?? prettyTag(tagName) : last
                .replace(/(?:^|[-/\s])\w/g, x => x.toUpperCase())
                .replace(/-/g, ' ')
                .replace('.html', '');
            return {
                tagName,
                primaryElementName,
                permalink,
                slug,
                title,
                filePath,
                manifest,
                ...demo
            };
        });
    }
}
//# sourceMappingURL=Manifest.js.map