import { HandlerContext, Project, ReviewComment } from "@atomist/automation-client";
import { SdmContext } from "@atomist/sdm";
import { GitCoordinate } from "../support/messages";
import { GetFpTargets } from "../typings/types";
import { Ideal } from "./Ideal";
/**
 * Fingerprint interface. An Aspect can emit zero or more fingerprints,
 * which must have the same data type.
 * @param DATA type parameter for data
 */
export interface FP<DATA = any> {
    type?: string;
    name: string;
    sha: string;
    data: DATA;
    version?: string;
    abbreviation?: string;
    /**
     * Path within the repository. Undefined means root.
     */
    path?: string;
}
export interface Vote {
    abstain: boolean;
    decision?: string;
    name?: string;
    fingerprint?: FP;
    fpTarget?: FP;
    diff?: Diff;
    text?: string;
    summary?: {
        title: string;
        description: string;
    };
}
/**
 * Difference between two fingerprints
 */
export interface Diff {
    from: FP;
    to: FP;
    data: {
        from: any[];
        to: any[];
    };
    owner: string;
    repo: string;
    sha: string;
    providerId: string;
    channel: string;
    branch: string;
}
/**
 * Extract fingerprint(s) from the given project.
 * Return undefined or the empty array if no fingerprints found.
 */
export declare type ExtractFingerprint<FPI extends FP = FP> = (p: Project) => Promise<FPI | FPI[]>;
export declare type FingerprintSelector = (fingerprint: FP) => boolean;
/**
 * Apply the given fingerprint to the project
 */
export declare type ApplyFingerprint<FPI extends FP = FP> = (p: Project, fp: FPI) => Promise<boolean>;
export interface DiffSummary {
    title: string;
    description: string;
}
export declare type DiffSummaryFingerprint = (diff: Diff, target: FP) => DiffSummary;
/**
 * Implemented by types that know how to compare two fingerprints,
 * for example by quality or up-to-dateness
 */
export interface FingerprintComparator<FPI extends FP = FP> {
    readonly name: string;
    comparator: (a: FPI, b: FPI) => number;
}
/**
 * Common properties for all aspects.
 * Aspects add the ability to manage a particular type of fingerprint:
 * for example, helping with convergence across an organization and supporting
 * visualization. Aspects are typically extracted from a Project (see Aspect)
 * but may also be built from existing fingerprints (AtomicAspect) or derived from
 * an intermediate representation such as a ProjectAnalysis (DerivedAspect).
 * The structure (that is, the data payload) of all fingerprints emitted by an aspect
 * should be the same.
 */
export interface BaseAspect<FPI extends FP = FP> {
    /**
     * Displayable name of this aspect. Used only for reporting.
     * Set to undefined to prevent this aspect influencing
     * display to users.
     */
    readonly displayName: string;
    /**
     * prefix for all fingerprints that are emitted by this Aspect
     */
    readonly name: string;
    /**
     * Link to documentation for this Aspect. This can help people
     * understand the results graphs and results from the analysis
     * enabled here.
     *
     * You might provide a link to the typedoc for Aspects you define,
     * or an internal page describing why you created this and what
     * people can do about their results.
     */
    readonly documentationUrl?: string;
    /**
     * Function to apply the given fingerprint instance to a project
     */
    apply?: ApplyFingerprint<FPI>;
    summary?: DiffSummaryFingerprint;
    /**
     * Functions that can be used to compare fingerprint instances managed by this
     * aspect.
     */
    comparators?: Array<FingerprintComparator<FPI>>;
    /**
     * Convert a fingerprint value to a human readable string
     * fpi.data is a reasonable default
     */
    toDisplayableFingerprint?(fpi: FPI): string;
    /**
     * Convert a fingerprint name such as "npm-project-dep::atomist::automation-client"
     * to a human readable form such as "npm package @atomist/automation-client"
     * @param {string} fingerprintName
     * @return {string}
     */
    toDisplayableFingerprintName?(fingerprintName: string): string;
    /**
     * Validate the aspect. Return undefined or the empty array if there are no problems.
     * @return {Promise<ReviewComment[]>}
     */
    validate?(fpi: FPI): Promise<ReviewComment[]>;
    /**
     * Based on the given fingerprint type and name, suggest ideals
     * order of recommendation strength
     */
    suggestedIdeals?(type: string, fingerprintName: string): Promise<Ideal[]>;
    /**
     * Workflows to be invoked on a fingerprint change. This supports use cases such as
     * reacting to a potential impactful change and cascading changes to other projects.
     */
    workflows?: FingerprintDiffHandler[];
    /**
     * Indications about how to calculate stats for this aspect across
     * multiple projects. An aspect without AspectStats will have its entropy
     * calculated by default.
     */
    stats?: AspectStats;
    /**
     * Does this aspect apply only to the root of a repository, rather than multiple subprojects?
     */
    readonly baseOnly?: boolean;
}
/**
 * Type for default stats that can be calculated on any feature.
 */
export declare type DefaultStat = "entropy";
/**
 * Type to use to customize calculation of default stats, such as entropy.
 * By default, all default stats are calculated and exposed.
 * To disable any, set a value of false for the key (such as "entropy"). A value of true
 * continues to include the stat.
 */
export declare type DefaultStatStatus = Partial<Record<DefaultStat, boolean>>;
/**
 * Indication about how to calculate custom stats across multiple projects for an Aspect.
 */
export interface AspectStats {
    /**
     * Set the status for calculating and exposing default stats, such as entropy.
     * Some may be irrelevant for this aspect.
     * Default is to calculate all stats.
     */
    defaultStatStatus?: DefaultStatStatus;
    /**
     * Path inside JSON data structure to compute mean, stdev etc.
     * The value at this path must be numeric. If an aspect appears to need multiple
     * basicStatsPaths, break it up into finer grained aspects.
     */
    basicStatsPath?: string;
}
/**
 * Does this aspect support entropy, or is it turned off?
 */
export declare function supportsEntropy(ba: BaseAspect): boolean;
/**
 * Aspect that extracts fingerprints directly from a Project.
 */
export interface Aspect<FPI extends FP = FP> extends BaseAspect<FPI> {
    /**
     * Function to extract fingerprint(s) from this project
     */
    extract: ExtractFingerprint<FPI>;
}
export interface DiffContext extends Diff {
    targets: GetFpTargets.Query;
}
export declare type FingerprintDiffHandler = (context: SdmContext, diff: DiffContext, aspect: Aspect) => Promise<Vote>;
/**
 * Handles differences between fingerprints across pushes and between targets.
 * Different strategies can be used to handle PushImpactEventHandlers.
 *
 */
export interface FingerprintHandler {
    /**
     * Is this handler able to manage this fingerprint instance?
     */
    selector: (name: FP) => boolean;
    /**
     * Called when shas differ across pushes
     * @param {HandlerContext} context
     * @param {Diff} diff
     * @return {Promise<Vote>}
     */
    diffHandler?: FingerprintDiffHandler;
    /**
     * Called when target fingerprint differs from current fingerprint
     * @param {HandlerContext} context
     * @param {Diff} diff
     * @return {Promise<Vote>}
     */
    handler?: FingerprintDiffHandler;
    /**
     * For collecting results on all fingerprint diff handlers
     */
    ballot?: (context: HandlerContext, votes: Vote[], coord: GitCoordinate, channel: string) => Promise<any>;
}
