/**
 * Media SEO scoring.
 *
 * Pure, dependency-free functions that derive an SEO score and a list of
 * actionable issues from a media asset's metadata. The score is intentionally
 * *derived* (never persisted) so it can never drift out of sync with the
 * underlying metadata — every read recomputes it from the current fields.
 *
 * The weights below are the contract the admin SEO drawer, the SEO Audit
 * table, and the `validateMediaSEO` MCP tool all share. Changing a weight is a
 * behavioural change to every surface that shows a media score, so keep the
 * unit tests in `__tests__/seo.test.ts` as the source of truth.
 */
/** Coarse asset class derived from a MIME type. */
export type MediaKind = 'image' | 'video' | 'pdf' | 'svg' | 'audio' | 'other';
export type MediaSeoGrade = 'good' | 'needs-work' | 'poor' | 'critical';
export type MediaSeoSeverity = 'critical' | 'high' | 'medium' | 'low';
/** A single, actionable SEO problem with a stable machine-readable `type`. */
export interface MediaSeoIssue {
    /** Stable identifier, e.g. `missing-alt`. Safe to switch/route on. */
    type: string;
    severity: MediaSeoSeverity;
    /** Human-readable, operator-safe description. */
    message: string;
    /** The asset field this issue maps to, when applicable. */
    field?: string;
    /** Whether the AI metadata flow can plausibly fix this issue. */
    fixableWithAI: boolean;
}
export interface MediaSeoScoreResult {
    /** 0–100, integer. */
    score: number;
    grade: MediaSeoGrade;
    issues: MediaSeoIssue[];
}
/** The metadata subset the score depends on. */
export interface MediaSeoInput {
    fileName?: string | null;
    mimeType?: string | null;
    altText?: string | null;
    title?: string | null;
    caption?: string | null;
    description?: string | null;
    focusKeyword?: string | null;
    sizeBytes?: number | null;
    width?: number | null;
    height?: number | null;
}
export interface MediaSeoOptions {
    /**
     * Bytes above which an image is flagged as oversized. Defaults to 2 MB —
     * large enough to allow a quality hero image, small enough to flag
     * un-optimised originals. Set from `config.media.maxImageSeoBytes`.
     */
    maxImageBytes?: number;
}
/** SEO weights. Must sum to 100. */
export declare const MEDIA_SEO_WEIGHTS: {
    readonly altText: 30;
    readonly title: 20;
    readonly description: 20;
    readonly caption: 10;
    readonly descriptiveFileName: 10;
    readonly focusKeyword: 10;
};
/** Map a MIME type to a coarse {@link MediaKind}. */
export declare function mediaKind(mimeType?: string | null): MediaKind;
/**
 * Whether a filename is generic/non-descriptive (e.g. `IMG_4892.jpg`). A
 * descriptive name needs at least one alphabetic run of 3+ chars and must not
 * match a known camera/screenshot/default pattern.
 */
export declare function isGenericFilename(fileName?: string | null): boolean;
/** Map a numeric score to a grade bucket. */
export declare function gradeForScore(score: number): MediaSeoGrade;
/**
 * Compute the SEO score (0–100) and issue list for a media asset.
 *
 * Scoring (weights in {@link MEDIA_SEO_WEIGHTS}, sum 100):
 *   alt text +30, title +20, description +20, caption +10,
 *   descriptive filename +10, focus keyword +10.
 *
 * Issues are additive context and do not subtract from the score directly —
 * e.g. an oversized image still scores on metadata, but surfaces an
 * `oversized-image` issue operators can act on.
 */
export declare function calculateMediaSeoScore(input: MediaSeoInput, options?: MediaSeoOptions): MediaSeoScoreResult;
//# sourceMappingURL=seo.d.ts.map