import { Cacheable, CacheableMemory } from "cacheable";
import { Hookified, HookifiedOptions } from "hookified";

//#region src/engine-interface.d.ts
type EngineInterface = {
  names: string[];
  engine: any;
  opts?: Record<string, unknown>;
  rootTemplatePath?: string;
  render(source: string, data?: Record<string, unknown>): Promise<string>;
  renderSync(source: string, data?: Record<string, unknown>): string;
};
//#endregion
//#region src/engine-map.d.ts
declare class EngineMap {
  private readonly _mappings;
  set(name: string, extensions: string[]): void;
  delete(name: string): void;
  deleteExtension(name: string, extension: string): void;
  get(name: string): string[] | undefined;
  getName(extension: string): string | undefined;
}
//#endregion
//#region src/base-engine.d.ts
declare class BaseEngine {
  names: string[];
  opts?: Record<string, unknown>;
  engine: any;
  rootTemplatePath?: string;
  private _extensions;
  getExtensions(): string[];
  setExtensions(extensions: string[]): void;
  deleteExtension(name: string): void;
}
//#endregion
//#region src/engines/ejs.d.ts
declare class EJS extends BaseEngine implements EngineInterface {
  constructor(options?: Record<string, unknown>);
  render(source: string, data?: Record<string, unknown>): Promise<string>;
  renderSync(source: string, data?: Record<string, unknown>): string;
}
//#endregion
//#region src/engines/handlebars.d.ts
declare class Handlebars extends BaseEngine implements EngineInterface {
  partialsPath: string[];
  constructor(options?: Record<string, unknown>);
  render(source: string, data?: Record<string, unknown>): Promise<string>;
  renderSync(source: string, data?: Record<string, unknown>): string;
  initPartials(): void;
  registerPartials(partialsPath: string): boolean;
}
//#endregion
//#region src/engines/liquid.d.ts
declare class Liquid extends BaseEngine implements EngineInterface {
  constructor(options?: Record<string, unknown>);
  render(source: string, data?: Record<string, unknown>): Promise<string>;
  renderSync(source: string, data?: Record<string, unknown>): string;
}
//#endregion
//#region src/engines/markdown.d.ts
declare class Markdown extends BaseEngine implements EngineInterface {
  constructor(options?: Record<string, unknown>);
  render(source: string, data?: Record<string, unknown>): Promise<string>;
  renderSync(source: string, data?: Record<string, unknown>): string;
}
//#endregion
//#region src/engines/nunjucks.d.ts
declare class Nunjucks extends BaseEngine implements EngineInterface {
  constructor(options?: Record<string, unknown>);
  render(source: string, data?: Record<string, unknown>): Promise<string>;
  renderSync(source: string, data?: Record<string, unknown>): string;
}
//#endregion
//#region src/engines/pug.d.ts
declare class Pug extends BaseEngine implements EngineInterface {
  constructor(options?: Record<string, unknown>);
  render(source: string, data?: Record<string, unknown>): Promise<string>;
  renderSync(source: string, data?: Record<string, unknown>): string;
}
//#endregion
//#region src/ecto.d.ts
type EctoOptions = {
  /**
   * The default engine to use. This can be 'ejs', 'markdown', 'pug', 'nunjucks', 'handlebars', 'liquid'
   * @default 'ejs'
   * @type {string}
   */
  defaultEngine?: string;
  /**
   * The engine options to pass to each engine
   * @type {Record<string, Record<string, unknown>>}
   * @default {}
   * @example
   * {
   * 	nunjucks: {
   * 		autoescape: true
   * 	},
   * 	markdown: {
   * 		html: true
   * 	}
   * }
   */
  engineOptions?: Record<string, Record<string, unknown>>;
  /**
   * Caching for async rendered templates. If set to true, it will use the default cacheable options.
   * If set to Cacheable instantce, it will use the provided cacheable instance.
   * @type {boolean | Cacheable}
   * @default false
   */
  cache?: boolean | Cacheable;
  /**
   * If set to true, it will cache the rendered templates synchronously when running renderSync.
   * If set to CacheableMemory instance, it will use the provided cacheable memory instance.
   * @type {boolean | CacheableMemory}
   * @default false
   */
  cacheSync?: boolean | CacheableMemory;
} & HookifiedOptions;
/**
 * Context passed to beforeRender and beforeRenderSync hooks
 */
type RenderContext = {
  source: string;
  data?: Record<string, unknown>;
  engineName: string;
  rootTemplatePath?: string;
  filePathOutput?: string;
  cached: boolean;
};
/**
 * Result passed to afterRender and afterRenderSync hooks
 */
type RenderResult = {
  result: string;
  context: RenderContext;
};
declare enum EctoEvents {
  cacheHit = "cacheHit",
  cacheMiss = "cacheMiss",
  warn = "warn",
  error = "error",
  beforeRender = "beforeRender",
  afterRender = "afterRender",
  beforeRenderSync = "beforeRenderSync",
  afterRenderSync = "afterRenderSync"
}
declare class Ecto extends Hookified {
  private readonly _mapping;
  private readonly _engines;
  private _cache;
  private _cacheSync;
  private _defaultEngine;
  private readonly _ejs;
  private readonly _markdown;
  private readonly _pug;
  private readonly _nunjucks;
  private readonly _handlebars;
  private readonly _liquid;
  /**
   * Ecto constructor
   * @param {EctoOptions} [options] - The options for the ecto engine
   */
  constructor(options?: EctoOptions);
  /**
   * Get the default engine
   * @returns {string} - the engine name such as 'ejs', 'markdown', 'pug', 'nunjucks', 'handlebars', 'liquid'
   */
  get defaultEngine(): string;
  /**
   * Set the default engine
   * @param {string} value the engine name such as 'ejs', 'markdown', 'pug', 'nunjucks', 'handlebars', 'liquid'
   */
  set defaultEngine(value: string);
  /**
   * Get the cacheable instance
   * @returns {Cacheable | undefined} - The cacheable instance or undefined if caching is disabled
   */
  get cache(): Cacheable | undefined;
  /**
   * Set the cacheable instance
   * @param {Cacheable | undefined} value - The cacheable instance to set. If set to undefined, caching will be disabled.
   */
  set cache(value: Cacheable | undefined);
  /**
   * Get the cacheable memory instance
   * @returns {CacheableMemory | undefined} - The cacheable memory instance or undefined if caching is disabled
   */
  get cacheSync(): CacheableMemory | undefined;
  /**
   * Set the cacheable memory instance
   * @param {CacheableMemory | undefined} value - The cacheable memory instance to set. If set to undefined, caching will be disabled.
   */
  set cacheSync(value: CacheableMemory | undefined);
  /**
   * Get the Engine Mappings. This is used to map file extensions to engines
   * @returns {EngineMap}
   */
  get mappings(): EngineMap;
  /**
   * Get the EJS Engine
   * @returns {EJS}
   */
  get ejs(): EJS;
  /**
   * Get the Markdown Engine
   * @returns {Markdown}
   */
  get markdown(): Markdown;
  /**
   * Get the Pug Engine
   * @returns {Pug}
   */
  get pug(): Pug;
  /**
   * Get the Nunjucks Engine
   * @returns {Nunjucks}
   */
  get nunjucks(): Nunjucks;
  /**
   * Get the Handlebars Engine
   * @returns {Handlebars}
   */
  get handlebars(): Handlebars;
  /**
   * Get the Liquid Engine
   * @returns {Liquid}
   */
  get liquid(): Liquid;
  /**
   * Asynchronously render a template source with data using the specified engine
   * @param {string} source - The template source string to render
   * @param {Record<string, unknown>} [data] - Data object to pass to the template engine
   * @param {string} [engineName] - Name of the engine to use (e.g., 'ejs', 'pug'). Defaults to defaultEngine
   * @param {string} [rootTemplatePath] - Root directory path for template includes/partials resolution
   * @param {string} [filePathOutput] - Optional file path to write the rendered output to
   * @returns {Promise<string>} The rendered template output as a string
   * @example
   * const result = await ecto.render('<%= name %>', { name: 'World' }, 'ejs');
   */
  render(source: string, data?: Record<string, unknown>, engineName?: string, rootTemplatePath?: string, filePathOutput?: string): Promise<string>;
  /**
   * Synchronously render a template source with data using the specified engine
   * @param {string} source - The template source string to render
   * @param {Record<string, unknown>} [data] - Data object to pass to the template engine
   * @param {string} [engineName] - Name of the engine to use (e.g., 'ejs', 'pug'). Defaults to defaultEngine
   * @param {string} [rootTemplatePath] - Root directory path for template includes/partials resolution
   * @param {string} [filePathOutput] - Optional file path to write the rendered output to
   * @returns {string} The rendered template output as a string
   * @example
   * const result = ecto.renderSync('<%= name %>', { name: 'World' }, 'ejs');
   */
  renderSync(source: string, data?: Record<string, unknown>, engineName?: string, rootTemplatePath?: string, filePathOutput?: string): string;
  /**
   * Asynchronously render a template from a file path
   * @param {string} filePath - Path to the template file to render
   * @param {Record<string, unknown>} [data] - Data object to pass to the template engine
   * @param {string} [rootTemplatePath] - Root directory for template includes. Defaults to file's directory
   * @param {string} [filePathOutput] - Optional file path to write the rendered output to
   * @param {string} [engineName] - Engine to use. If not specified, determined from file extension
   * @returns {Promise<string>} The rendered template output as a string
   * @example
   * const result = await ecto.renderFromFile('./templates/index.ejs', { title: 'Home' });
   */
  renderFromFile(filePath: string, data?: Record<string, unknown>, rootTemplatePath?: string, filePathOutput?: string, engineName?: string): Promise<string>;
  /**
   * Synchronously render a template from a file path
   * @param {string} filePath - Path to the template file to render
   * @param {Record<string, unknown>} [data] - Data object to pass to the template engine
   * @param {string} [rootTemplatePath] - Root directory for template includes. Defaults to file's directory
   * @param {string} [filePathOutput] - Optional file path to write the rendered output to
   * @param {string} [engineName] - Engine to use. If not specified, determined from file extension
   * @returns {string} The rendered template output as a string
   * @example
   * const result = ecto.renderFromFileSync('./templates/index.ejs', { title: 'Home' });
   */
  renderFromFileSync(filePath: string, data?: Record<string, unknown>, rootTemplatePath?: string, filePathOutput?: string, engineName?: string): string;
  /**
   * Asynchronously ensure that the directory path for a file exists, creating it if necessary
   * @param {string} path - The full file path (directories will be extracted from this)
   * @returns {Promise<void>}
   * @example
   * await ecto.ensureFilePath('/path/to/file.txt');
   */
  ensureFilePath(path: string): Promise<void>;
  /**
   * Synchronously ensure that the directory path for a file exists, creating it if necessary
   * @param {string} path - The full file path (directories will be extracted from this)
   * @returns {void}
   * @example
   * ecto.ensureFilePathSync('/path/to/file.txt');
   */
  ensureFilePathSync(path: string): void;
  /**
   * Determine the appropriate template engine based on a file's extension
   * @param {string} filePath - The file path to analyze
   * @returns {string} The engine name (e.g., 'ejs', 'markdown', 'pug', 'nunjucks', 'handlebars', 'liquid')
   * @example
   * const engine = ecto.getEngineByFilePath('template.ejs'); // Returns 'ejs'
   */
  getEngineByFilePath(filePath: string): string;
  /**
   * Asynchronously find a template file in a directory by name, regardless of extension
   * @param {string} path - Directory path to search in
   * @param {string} templateName - Template name without extension
   * @returns {Promise<string>} Full path to the found template file, or empty string if not found
   * @example
   * const templatePath = await ecto.findTemplateWithoutExtension('./templates', 'index');
   */
  findTemplateWithoutExtension(path: string, templateName: string): Promise<string>;
  /**
   * Synchronously find a template file in a directory by name, regardless of extension
   * @param {string} path - Directory path to search in
   * @param {string} templateName - Template name without extension
   * @returns {string} Full path to the found template file, or empty string if not found
   * @example
   * const templatePath = ecto.findTemplateWithoutExtensionSync('./templates', 'index');
   */
  findTemplateWithoutExtensionSync(path: string, templateName: string): string;
  /**
   * Check if the given engine name is valid and registered in Ecto
   * @param {string} [engineName] - The engine name to validate
   * @returns {boolean} True if the engine is valid and registered, false otherwise
   * @example
   * const isValid = ecto.isValidEngine('ejs'); // Returns true
   */
  isValidEngine(engineName?: string): boolean;
  /**
   * Detect the template engine from a template string by analyzing its syntax
   * @param {string} source - The template source string to analyze
   * @returns {string} The detected engine name ('ejs', 'markdown', 'pug', 'nunjucks', 'handlebars', 'liquid') or the default engine
   * @example
   * const engine = ecto.detectEngine('<%= name %>'); // Returns 'ejs'
   * const engine2 = ecto.detectEngine('{{name}}'); // Returns 'handlebars' or 'liquid'
   * const engine3 = ecto.detectEngine('# Heading'); // Returns 'markdown'
   * const engine4 = ecto.detectEngine('plain text'); // Returns defaultEngine (e.g., 'ejs')
   */
  detectEngine(source: string): string;
  /**
   * Register all engine mappings between engine names and file extensions
   * @returns {void}
   * @private
   */
  registerEngineMappings(): void;
  /**
   * Get the render engine instance by name
   * @param {string} engineName - The name of the engine to retrieve
   * @returns {EngineInterface} The engine instance (defaults to EJS if not found)
   * @example
   * const engine = ecto.getRenderEngine('pug');
   */
  getRenderEngine(engineName: string): EngineInterface;
  /**
   * Check if the source content contains front matter (YAML metadata)
   * @param {string} source - The source content to check
   * @returns {boolean} True if front matter is present, false otherwise
   * @example
   * const hasFM = ecto.hasFrontMatter('---\ntitle: Test\n---\nContent');
   */
  hasFrontMatter(source: string): boolean;
  /**
   * Extract front matter data from the source content
   * @param {string} source - The source content containing front matter
   * @returns {Record<string, unknown>} Parsed front matter as an object
   * @example
   * const data = ecto.getFrontMatter('---\ntitle: Test\n---\nContent');
   */
  getFrontMatter(source: string): Record<string, unknown>;
  /**
   * Set or replace front matter in the source content
   * @param {string} source - The source content
   * @param {Record<string, unknown>} data - The front matter data to set
   * @returns {string} The source content with updated front matter
   * @example
   * const updated = ecto.setFrontMatter('Content', { title: 'New Title' });
   */
  setFrontMatter(source: string, data: Record<string, unknown>): string;
  /**
   * Remove front matter from the source content, returning only the body
   * @param {string} source - The source content with front matter
   * @returns {string} The source content without front matter
   * @example
   * const body = ecto.removeFrontMatter('---\ntitle: Test\n---\nContent');
   */
  removeFrontMatter(source: string): string;
  /**
   * Write content to a file asynchronously, creating directories if needed
   * @private
   * @param {string} [filePath] - The path to write the file to
   * @param {string} [source] - The content to write to the file
   * @returns {Promise<void>}
   */
  private writeFile;
  /**
   * Write content to a file synchronously, creating directories if needed
   * @private
   * @param {string} [filePath] - The path to write the file to
   * @param {string} [source] - The content to write to the file
   * @returns {void}
   */
  private writeFileSync;
}
//#endregion
export { type BaseEngine, EJS, Ecto, EctoEvents, EctoOptions, type EngineInterface, Handlebars, Liquid, Markdown, Nunjucks, Pug, RenderContext, RenderResult };