import { ILogger, IPargv } from 'pargv';

export type BeforeRender = { (template?: ITemplate, done?: { () }) };

export type AfterRender = { (template?: ITemplate) };

export type NodeCallback = { (err?: any, data?: any) };

export type InjectCallback = { (line: string, data: string, done: { (line: string, data: string) }) }

export interface IMetadata {
  component?: string;   // the component name generated from command line.
  [key: string]: any;   // other metadata passed in template or on rendering.
}

export interface IPartials {
  [key: string]: string | ITemplate;
}

export interface ITemplate {

  name?: string;                // name of template used ONLY when passing static templates.
  ext?: string;                 // extension to use when rendered.
  suffix?: string;              // suffix to be added to the component name.
  casing?: 'lower' | 'upper' | 'camel' | 'title' | 'capitalize';  // component name case.
  injects?: any[];
  path?: string;                // the path to the template if not static defined template.
  pathNormalized?: string;      // the path without template extension.
  metadata?: IMetadata;         // metadata for template rendering.
  body?: string;                // the template body.
  beforeRender?: BeforeRender;  // the callback before rendering/compiling template.
  afterRender?: AfterRender;    // the callback after rending the template to file.
  outputPath?: string;          // the path to output the template to.
  raw?: string;                 // a static template that has not been parsed.
  rendered?: string;            // the rendered string result.
  partials?: IPartials;         // object conatianing template's partials.
  isPartial?: boolean;          // indicates the template is a partial.

}

export interface ITemplates {
  [key: string]: ITemplate;
}

export interface IRegisterOptions {
  name: string;
  template: string;
  partials?: string | string[] | IPartials;
  beforeRender?: BeforeRender;
  afterRender?: AfterRender;
}

export interface IRegister {
  partials(...args: any[]): IRegister;
  partials(partials: string | string[] | IPartials): IRegister;
  beforeRender(beforeRender: BeforeRender): IRegister;
  afterRender(afterRender: AfterRender): IRegister;
}

export interface IInject {
  filename: string;
  find: string | RegExp;
  insert: string | string[];
  strategy: 'before' | 'after' | 'first' | 'last' | 'replace';
  done: NodeCallback;
}

export interface IMustrOptions {
  configDir?: string;     // the Muster dir containing templates and register.
  outputDir?: string;     // the output directory when templates are rendered.
  templateExt?: string;   // the extension for templates usually .tpl.
}

export interface IMustr {

  cwd: string;
  log: ILogger;
  registerPath: string;
  templatesPath: string;
  outputPath: string;
  templatesGlob: string[];
  templates: ITemplates;
  options: IMustrOptions;

  init(force?: boolean): void;
  load(): IMustr;
  register(options: IRegisterOptions): IRegister;
  register(name: string | IRegisterOptions, template?: string): IRegister;
  configure(name: string, metadata?: IMetadata): ITemplate;
  configure(name: string, output?: string | IMetadata, metadata?: IMetadata): ITemplate;
  render(template: ITemplate, done?: NodeCallback): void;
  render(template: ITemplate, metadata?: IMetadata, done?: NodeCallback): void;
  render(name: string | ITemplate, output?: string | IMetadata | NodeCallback, metadata?: IMetadata | NodeCallback, done?: NodeCallback): void;
  inject(options: IInject, done?: NodeCallback): void;
  inject(filename: string | IInject,
    find: string | RegExp | NodeCallback,
    insert: string | string[],
    strategy: 'before' | 'after' | 'first' | 'last' | 'replace',
    done?: NodeCallback): void;
  transformCase(str: string, to: string): string;

}