import { VFile } from 'vfile';
import { FrozenProcessor, PluggableList } from 'unified';
import { Options } from 'remark-rehype';
import * as unist from 'unist';
import { Parent, Node } from 'unist';
import { WithContext, Thing } from 'schema-dts';
import { Result } from 'hastscript';
import * as hast from 'hast';
import { ElementContent, Element as Element$1 } from 'hast';
import { Test } from 'unist-util-is';

type File = [string, string];
type Files = File[];


type Schema = WithContext<Thing>;

type Tree = ReturnType<FrozenProcessor['parse']>;

type Transformers = ((vFile: VFile) => PluggableList) | PluggableList;

type PageType = 'page' | string;

type FrontMatter = Partial<Meta>;

type LayoutFn = (children: Parent['children'], meta: Meta) => Result | Result[];

declare module 'VFile' {
  interface VFileDataMap {
    matter: FrontMatter;
    tree: Tree;
    structuredContent: Schema;
    meta: Meta;
    pathname: string;
    vFiles: Record<PageType, VFile[]>;
  }
}

interface TransferrableOptions {
  host: string;
  name: string;
  language: string;
  sitemap: boolean;
  manifest: false | string;
  feed: false | Feed;
}

type IgnorePattern = string | RegExp | ((file: string) => Boolean);

interface RamblerOptions extends Partial<TransferrableOptions> {
  contentDir?: string | string[];
  contentFiles?: string | string[];
  publicDir?: string;
  outputDir?: string;
  watchDir?: string | string[];
  ignorePattern?: IgnorePattern | IgnorePattern[];
  verbose?: boolean;
  watch?: boolean;
  search?: boolean | Search;

  formatMarkdown?: boolean;

  linkFiles?: boolean;

  type?: (filename: string, matter: FrontMatter) => PageType;

  parsers?: PluggableList;
  remarkPlugins?: PluggableList;
  remarkRehypeOptions?: Options;
  rehypePlugins?: Transformers;
  renderers?: PluggableList;

  directives?: Record<string, any>;
  defaults?: Record<PageType, Partial<PageOptions>>;
}

interface PageOptions {
  layout: LayoutFn;
  author: Author;
  publisher: Publisher;
  title: string;
  description?: string;
  prefetch?: string;
  published?: Date;
  modified?: Date;
  stylesheets: string[];
  scripts: string[];
  sameAs?: string[];
  draft?: boolean;
  image?: Image;
  tags?: string[];
  logo: Logo;
  icon: Image;
  structuredContent?: {
    '@type': 'WebSite' | 'Article';
  };
  [key: string]: unknown;
}

interface Meta extends PageOptions, TransferrableOptions {
  type: string;
  pathname: string;
  href: string;
  bundledStylesheets: string[];
  bundledScripts: string[];
  pageStylesheets: string[];
  pageScripts: string[];
}

type Feed = {
  pathname: string;
  title: string;
  description?: string;
  author?: string;
  tags?: string[];
  filter?: (type: PageType, vFile: VFile) => boolean;
};

type Search = {
  outputDir?: string;
  filter?: (type: PageType, vFile: VFile) => boolean;
};

interface Image {
  src: string;
  alt?: string;
}

interface Logo extends Image {
  href: string;
}

type Author = {
  name: string;
  href: string;
  twitter?: string;
};

type Publisher = {
  name: string;
  href: string;
  logo: Image;
};

type DirectiveVisitor = (node: Element, index: number, parent: Parent, vFile: VFile) => Element;

type Directives = Record<string, DirectiveVisitor>;

declare class MarkdownRambler {
    private options;
    constructor(options?: RamblerOptions);
    private setDefaultOptions;
    private getTransformers;
    /** @public */
    run(): Promise<void>;
    private getContentFiles;
    private bundleAssets;
    private copyAsset;
    private handleFile;
    private parseMarkdownFile;
    parseMarkdownVFile(vFile: VFile): Promise<VFile>;
    parseMarkdownFiles(files: Files): Promise<VFile[]>;
    renderMarkdownFiles(vFiles: VFile[]): Promise<VFile[]>;
    renderMarkdownFile(vFile: VFile): Promise<VFile>;
    renderFeed(vFiles: VFile[]): Promise<string>;
    private renderSitemap;
    private renderSearchIndex;
    watch(dirs: string[]): Promise<any[]>;
    private verbose;
}

declare const html: (strings: TemplateStringsArray, ...values: any[]) => hast.Element | hast.Element[];

declare const addScript: ({ src }: {
    src: any;
}) => (tree: any) => unist.Parent<unist.Node<unist.Data>, unist.Data>;

type VisitorCallback = (node: Parent, index: number, parent: Parent) => void;
declare const findElement: (tree: Parent, test: Test, callback: VisitorCallback) => void;
declare const append: (tree: Parent, test: Test, ...elements: ElementContent[]) => Parent<Node<unist.Data>, unist.Data>;
declare const insertBefore: (tree: Parent, test: Test, element: Element$1) => Parent<Node<unist.Data>, unist.Data>;
declare const insertBeforeStylesheets: (tree: Parent, element: Element$1) => Parent<Node<unist.Data>, unist.Data>;

export { DirectiveVisitor, Directives, MarkdownRambler, Meta, Transformers, addScript, append, findElement, html, insertBefore, insertBeforeStylesheets };
