import { createMetadataStore } from '../store.js';
import { layerExistsForEntity, mapEntityForResponse, paginate, readLayerFilesForEntity, sortByEntityId, } from '../utils.js';
const deriveTokenFormat = (artifactPath) => {
    if (!artifactPath) {
        return undefined;
    }
    const normalized = artifactPath.toLowerCase();
    if (normalized.includes('figma-variables/') && normalized.endsWith('.json')) {
        return 'figma';
    }
    if (normalized.endsWith('.scss')) {
        return 'sass';
    }
    if (normalized.endsWith('.js') || normalized.endsWith('.d.ts')) {
        return 'javascript';
    }
    if (normalized.endsWith('.css')) {
        return 'css';
    }
    return undefined;
};
const deriveTokenTheme = (artifactPath) => {
    if (!artifactPath) {
        return undefined;
    }
    const normalized = artifactPath
        .toLowerCase()
        .replace(/_/g, '-');
    if (normalized.includes('sick2025') && normalized.includes('dark')) {
        return 'sick2025-dark';
    }
    if (normalized.includes('sick2025') && normalized.includes('light')) {
        return 'sick2025-light';
    }
    if (normalized.includes('sick2018') && normalized.includes('dark')) {
        return 'sick2018-dark';
    }
    if (normalized.includes('sick2018') && normalized.includes('light')) {
        return 'sick2018-light';
    }
    return undefined;
};
/**
 * List tokens with optional filtering and pagination.
 * @param options Options for querying tokens, including filtering by status and tags, pagination, and layer/verbosity preferences.
 * @param storeOptions Options for configuring the metadata store.
 * @returns A promise that resolves to a public response containing the list of tokens and metadata.
 */
export const getTokens = async (options = {}, storeOptions = {}) => {
    const store = createMetadataStore(storeOptions);
    const index = await store.getIndex();
    const requestedLayer = options.layer ?? 'full';
    const requestedVerbosity = options.verbosity ?? 'readable';
    const entities = (await store.findEntities({
        kind: 'token',
        status: options.status,
        tags: options.tags,
    }));
    const sorted = sortByEntityId(entities);
    const hasRequestedLayer = sorted.every((entity) => layerExistsForEntity(entity, requestedLayer));
    if (options.strictLayer && !hasRequestedLayer) {
        return {
            data: [],
            errors: [{
                    code: 'LAYER_NOT_AVAILABLE',
                    details: {
                        requestedLayer,
                    },
                    message: `Requested layer "${requestedLayer}" is not available for all token entities.`,
                }],
            meta: {
                builtAt: index.builtAt,
                requestedLayer,
                requestedVerbosity,
                resolvedLayer: requestedLayer,
                schemaVersion: index.version,
                total: sorted.length,
                warnings: ['strictLayer=true and requested layer is unavailable for part of result set'],
            },
        };
    }
    const resolvedLayer = hasRequestedLayer ? requestedLayer : 'full';
    const paged = paginate(sorted, options.limit, options.offset);
    return {
        data: paged.map((entity) => mapEntityForResponse(entity, options)),
        meta: {
            builtAt: index.builtAt,
            requestedLayer,
            requestedVerbosity,
            resolvedLayer,
            schemaVersion: index.version,
            total: sorted.length,
            warnings: hasRequestedLayer ? undefined : [
                `Requested layer "${requestedLayer}" was unavailable; falling back to "full".`,
            ],
        },
    };
};
/**
 * Get token data for a specific format and theme, with options for pagination.
 * @param options Options for querying token data, including format, theme, pagination preferences.
 * @param storeOptions Options for configuring the metadata store.
 * @returns A promise that resolves to a public response containing the token data payload, or null if not found.
 */
export const getDataForTokens = async (options = {}, storeOptions = {}) => {
    const requestedFormat = options.format ?? 'css';
    const resolvedTheme = requestedFormat === 'css'
        ? (options.theme ?? 'sick2025-light')
        : options.theme;
    const metadata = await getTokens({
        includeLayerRefs: true,
        includeSources: false,
        layer: 'full',
    }, storeOptions);
    const warnings = [];
    if (requestedFormat !== 'css' && options.theme) {
        warnings.push(`Theme "${options.theme}" is ignored for format "${requestedFormat}".`);
    }
    const filteredEntities = metadata.data.filter((entity) => {
        const format = (entity.custom?.format)
            ?? deriveTokenFormat(entity.custom?.artifactPath);
        const theme = (entity.custom?.theme)
            ?? deriveTokenTheme(entity.custom?.artifactPath);
        if (format !== requestedFormat) {
            return false;
        }
        if (requestedFormat === 'css') {
            return theme === resolvedTheme;
        }
        return true;
    });
    const pagedEntities = paginate(filteredEntities, options.limit, options.offset);
    const store = createMetadataStore(storeOptions);
    const tokenEntries = (await Promise.all(pagedEntities.map(async (entity) => {
        const files = await readLayerFilesForEntity(store, entity, 'full');
        const format = (entity.custom?.format)
            ?? deriveTokenFormat(entity.custom?.artifactPath);
        const theme = (entity.custom?.theme)
            ?? deriveTokenTheme(entity.custom?.artifactPath);
        return files.map(({ content, ref }) => ({
            content,
            format,
            path: ref.path,
            theme,
            token: entity.id,
        }));
    }))).flat();
    return {
        data: {
            format: requestedFormat,
            theme: requestedFormat === 'css' ? resolvedTheme : undefined,
            tokens: tokenEntries,
            warnings: warnings.length > 0 ? warnings : undefined,
        },
        errors: metadata.errors,
        meta: {
            ...metadata.meta,
            total: filteredEntities.length,
            warnings: [
                ...(metadata.meta.warnings ?? []),
                ...warnings,
            ],
        },
    };
};
