import { type Struct } from 'superstruct';
import { type Value, type AdblockSyntax, type AnyRule, type Node } from '@adguard/agtree';
import { type AnySeverity } from './severity';
import { type CssTreeParsingContext, type CssTreeParsingContextToNode } from './helpers/css-tree-types';
/**
 * Represents any linter rule
 */
export type AnyLinterRule = LinterRule<any, any>;
/**
 * Type for rule configuration object
 */
export type LinterRuleConfigObject = {
    [key: string]: LinterRuleConfig;
};
/**
 * Type definition for the linter rule config, which can be:
 * - severity itself (number or string): `severity`
 * - one-element array with severity as the first element: `[severity]`
 * - n-element array with severity as the first element and other options as the rest: `[severity, ...options]`
 */
export type LinterRuleConfig = AnySeverity | LinterRuleConfigArray;
/**
 * Type definition for the linter rule config array, which can be:
 * - one-element array with severity as the first element: `[severity]`
 * - n-element array with severity as the first element and other options as the rest: `[severity, ...options]`
 */
export type LinterRuleConfigArray = [AnySeverity, ...unknown[]];
/**
 * Represents the metadata of a linter rule configuration
 */
export interface LinterRuleConfigMeta {
    /**
     * Default configuration of the rule
     */
    default: unknown;
    /**
     * Superstruct schema for the rule configuration (used for validation)
     */
    schema: Struct;
}
/**
 * Represents the metadata of a linter rule
 */
export interface LinterRuleMeta {
    /**
     * Linter rule severity. It can be off, warn, error or fatal.
     */
    severity: AnySeverity;
    /**
     * Configuration metadata (if the rule has any configuration)
     */
    config?: LinterRuleConfigMeta;
}
/**
 * Represents what events a linter rule can handle
 */
export interface LinterRuleEvents<StorageType = LinterRuleStorage<unknown>, ConfigType = unknown> {
    /**
     * Called before analyzing a filter list (before any rule is analyzed).
     * You can retrieve the filter list and other necessary information from the context.
     *
     * @param context - Linter context
     */
    onStartFilterList?: (context: GenericRuleContext<StorageType, ConfigType>) => void;
    /**
     * Called after analyzing a filter list (after all rules are analyzed).
     * You can retrieve the filter list and other necessary information from the context.
     *
     * @param context - Linter context
     */
    onEndFilterList?: (context: GenericRuleContext<StorageType, ConfigType>) => void;
    /**
     * Called when analyzing an adblock rule. This event is called for each rule, including comments.
     * You can retrieve the adblock rule and other necessary information from the context.
     *
     * @param context - Linter context
     */
    onRule?: (context: SpecificRuleContext<StorageType, ConfigType>) => void;
}
/**
 * Represents an AGLint rule
 */
export interface LinterRule<StorageType = LinterRuleStorage<unknown>, ConfigType = unknown> {
    /**
     * Basic data of the rule (metadata)
     */
    meta: LinterRuleMeta;
    /**
     * Events belonging to the rule
     */
    events: LinterRuleEvents<StorageType, ConfigType>;
}
/**
 * Represents the core linter configuration
 */
export interface LinterConfig {
    /**
     * Root configuration flag. If it's value is true, the configuration is root configuration.
     */
    root?: boolean;
    /**
     * Whether to allow inline configuration or not
     *
     * @example
     * ```adblock
     * ! aglint-disable-next-line
     * ```
     */
    allowInlineConfig?: boolean;
    /**
     * An array of configuration presets to extend
     */
    extends?: string[];
    /**
     * Specific adblock syntaxes to use for network rule modifiers validation.
     * Array of strings:
     * - `['Common']` (default)
     * - or any combination of `['AdGuard', 'uBlockOrigin', 'AdblockPlus']`.
     *
     * Can be set in the configuration file
     * or in the filter list as `Agent` type comment.
     *
     */
    syntax: AdblockSyntax[];
    /**
     * A map of rule names to their configuration
     */
    rules?: LinterRuleConfigObject;
}
/**
 * Type definition for the linter rule context getter function.
 *
 * @param rawValueNode The raw value node.
 * @param context The context, see {@link CssTreeParsingContext}.
 *
 * @returns The CSS node or `null` if the CSS could not be parsed.
 */
type CssNodeGetter = <T extends CssTreeParsingContext>(rawValueNode: Value<string>, context: T) => CssTreeParsingContextToNode[T] | null;
/**
 * Represents a linter context that is passed to the rules when their events are triggered
 */
export interface GenericRuleContext<StorageType = LinterRuleStorage<unknown>, ConfigType = unknown> {
    /**
     * Returns the clone of the shared linter configuration.
     *
     * @returns The shared linter configuration
     */
    getLinterConfig: () => LinterConfig;
    /**
     * Returns the raw content of the adblock filter list currently processed by the linter.
     *
     * @returns The raw adblock filter list content
     */
    getFilterListContent: () => string;
    /**
     * Returns whether a fix was requested from the linter. This is an optimization
     * for the linter, so it doesn't have to run the fixer if it's not needed.
     *
     * @returns `true` if fix is needed, `false` otherwise
     */
    fixingEnabled: () => boolean;
    /**
     * Storage for storing data between events. This storage is only visible to the rule.
     */
    storage: StorageType;
    /**
     * Additional config for the rule. This is unknown at this point, but the concrete
     * type is defined by the rule.
     */
    config: ConfigType;
    /**
     * Function for reporting problems to the linter.
     *
     * @param problem - The problem to report
     */
    report: (problem: LinterProblemReport) => void;
    /**
     * Returns the CSS node for the given raw value node and context.
     *
     * @param rawValueNode - The raw value node
     * @param context - The context, see {@link CssTreeParsingContext}.
     * For more information, please check https://github.com/csstree/csstree/blob/master/docs/parsing.md#context
     *
     * @returns The CSS node or `null` if the CSS could not be parsed
     *
     * @note When you call this function from a rule and it cannot parse the CSS,
     * it will automatically report a problem to the linter and marks your linter rule as the source.
     * Reported problem will have the same severity as the rule.
     */
    getCssNode: CssNodeGetter;
}
/**
 * Specialized linter context for the rule that is triggered when analyzing an adblock rule
 */
export interface SpecificRuleContext<StorageType = LinterRuleStorage<unknown>, ConfigType = unknown> extends GenericRuleContext<StorageType, ConfigType> {
    /**
     * Returns the AST of the adblock rule currently being iterated by the linter.
     *
     * @returns The actual adblock rule as AST
     */
    getActualAdblockRuleAst: () => AnyRule;
    /**
     * Returns the raw version of the adblock rule currently being iterated by the linter.
     *
     * @returns The actual adblock rule as original string
     */
    getActualAdblockRuleRaw: () => string;
    /**
     * Returns the line number that the linter is currently iterating.
     *
     * @returns The actual line number
     */
    getActualLine: () => number;
}
/**
 * Represents the location of a problem that detected by the linter
 */
export interface LinterPosition {
    /**
     * 1-based line number of the problem
     */
    startLine: number;
    /**
     * 0-based column number of the problem
     */
    startColumn: number;
    /**
     * 1-based line number of the problem
     */
    endLine: number;
    /**
     * 0-based column number of the problem
     */
    endColumn: number;
}
/**
 * Represents a problem report (this must be passed to context.report from the rules)
 */
export interface LinterProblemReport {
    /**
     * Text description of the problem
     */
    message: string;
    /**
     * Node that caused the problem. If provided, the linter will use its offsets to determine the problem location.
     */
    node?: Node;
    /**
     * Relative start offset to the start of the node that caused the problem.
     * Useful when you do not want to mark the whole node as problematic.
     *
     * @note Only takes effect when `node` is provided.
     */
    relativeNodeStartOffset?: number;
    /**
     * Relative start offset to the start of the node that caused the problem.
     * Useful when you do not want to mark the whole node as problematic.
     *
     * @note Only takes effect when `node` is provided.
     */
    relativeNodeEndOffset?: number;
    /**
     * The location of the problem
     */
    position?: LinterPosition;
    /**
     * Suggested fix for the problem
     */
    fix?: AnyRule | AnyRule[];
    /**
     * Severity of the problem, overrides the rule severity set in the meta property.
     * Needed for modifiers validation, e.g. deprecated modifiers which are still supported
     * but will not be supported in the future, so they are not recommended to use.
     */
    customSeverity?: AnySeverity;
}
/**
 * Represents a linter rule storage object that is passed as reference to
 * the rules when their events are triggered.
 *
 * Basically used internally by the linter, so no need to export this.
 */
export interface LinterRuleStorage<T = unknown> {
    [key: string]: T;
}
export {};
