/**
 * Default English translations for ApexDocs.
 * These can be overridden by users in their configuration.
 */
type Translations = {
    changelog: {
        title: string;
        newClasses: {
            heading: string;
            description: string;
        };
        newInterfaces: {
            heading: string;
            description: string;
        };
        newEnums: {
            heading: string;
            description: string;
        };
        newCustomObjects: {
            heading: string;
            description: string;
        };
        newTriggers: {
            heading: string;
            description: string;
        };
        removedTypes: {
            heading: string;
            description: string;
        };
        removedCustomObjects: {
            heading: string;
            description: string;
        };
        removedTriggers: {
            heading: string;
            description: string;
        };
        newOrModifiedMembers: {
            heading: string;
            description: string;
        };
        newOrRemovedCustomFields: {
            heading: string;
            description: string;
        };
        newOrRemovedCustomMetadataTypeRecords: {
            heading: string;
            description: string;
        };
        memberModifications: {
            newEnumValue: string;
            removedEnumValue: string;
            newMethod: string;
            removedMethod: string;
            newProperty: string;
            removedProperty: string;
            newField: string;
            removedField: string;
            newType: string;
            removedType: string;
            newCustomMetadataRecord: string;
            removedCustomMetadataRecord: string;
            newTrigger: string;
            removedTrigger: string;
        };
    };
    markdown: {
        sections: {
            methods: string;
            properties: string;
            fields: string;
            constructors: string;
            values: string;
            classes: string;
            enums: string;
            interfaces: string;
            namespace: string;
            records: string;
            publishBehavior: string;
        };
        details: {
            type: string;
            signature: string;
            group: string;
            author: string;
            date: string;
            see: string;
            possibleValues: string;
            parameters: string;
            throws: string;
            returnType: string;
            apiName: string;
            required: string;
            inlineHelpText: string;
            complianceGroup: string;
            securityClassification: string;
            protected: string;
        };
        typeSuffixes: {
            class: string;
            interface: string;
            enum: string;
            trigger: string;
        };
        triggerEvents: {
            beforeInsert: string;
            beforeUpdate: string;
            beforeDelete: string;
            afterInsert: string;
            afterUpdate: string;
            afterDelete: string;
            afterUndelete: string;
        };
        publishBehaviors: {
            publishImmediately: string;
            publishAfterCommit: string;
        };
        inheritance: {
            inheritance: string;
            implements: string;
        };
        lwc: {
            exposed: string;
            targets: string;
            targetConfigs: string;
            properties: string;
        };
    };
};

/**
 * User-provided partial translations that can override the defaults.
 */
type UserTranslations = DeepPartial<Translations>;
/**
 * Utility type to make all properties in T optional recursively.
 */
type DeepPartial<T> = {
    [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

// Apex Reflection-based types


// Renderable types

type ReferenceGuideReference = {
  reference: DocPageReference;
  title: Link;
  description: RenderableContent[] | null;
};

type Link = {
  readonly __type: 'link';
  title: string;
  url: string;
};

type EmptyLine = {
  __type: 'empty-line';
};

type StringOrLink = string | Link;

type RenderableContent = StringOrLink | EmptyLine | CodeBlock | InlineCode;

type EnumValue = {
  value: string;
  description?: RenderableContent[];
};

type CustomTag = {
  name: string;
  description?: RenderableContent[];
};

/**
 * Represents an annotation to a top-level type. For example, @NamespaceAccessible.
 */
type Annotation = string;

type CodeBlock = {
  readonly __type: 'code-block';
  language: string;
  content: string[];
};

type InlineCode = {
  readonly __type: 'inline-code';
  content: string;
};

type RenderableDocumentation = {
  annotations?: Annotation[];
  description?: RenderableContent[];
  customTags?: CustomTag[];
  example?: RenderableSection<RenderableContent[] | undefined>;
  group?: string;
  author?: string;
  date?: string;
  sees?: StringOrLink[];
};

type RenderableType = {
  namespace?: string;
  headingLevel: number;
  heading: string;
  name: string;
  meta: {
    accessModifier: string;
  };
  doc: RenderableDocumentation;
};

type RenderableMethodParameter = {
  name: string;
  type: StringOrLink;
  description?: RenderableContent[];
};

type TypeSource = {
  type: StringOrLink;
  description?: RenderableContent[];
};

type RenderableConstructor = {
  headingLevel: number;
  heading: string;
  signature: RenderableSection<CodeBlock>;
  parameters?: RenderableSection<RenderableMethodParameter[] | undefined>;
  throws?: RenderableSection<TypeSource[] | undefined>;
  doc: RenderableDocumentation;
};

type RenderableMethod = {
  doc: RenderableDocumentation;
  headingLevel: number;
  heading: string;
  signature: RenderableSection<CodeBlock>;
  parameters: RenderableSection<RenderableMethodParameter[] | undefined>;
  returnType: RenderableSection<TypeSource>;
  throws: RenderableSection<TypeSource[] | undefined>;
  inherited?: boolean;
};

type RenderableApexField = {
  headingLevel: number;
  heading: string;
  type: RenderableSection<StringOrLink>;
  accessModifier: string;
  inherited?: boolean;
  signature: RenderableSection<CodeBlock>;
  doc: RenderableDocumentation;
};

type RenderableSection<T> = {
  headingLevel: number;
  heading: string;
  value: T;
};

type GroupedMember<T> = RenderableSection<T[]> & { groupDescription: string | undefined };

type RenderableClass = RenderableType & {
  type: 'class';
  extends?: StringOrLink[];
  implements?: StringOrLink[];
  classModifier?: string;
  sharingModifier?: string;
  constructors: RenderableSection<RenderableConstructor[] | GroupedMember<RenderableConstructor>[]> & {
    isGrouped: boolean;
  };
  methods: RenderableSection<RenderableMethod[] | GroupedMember<RenderableMethod>[]> & { isGrouped: boolean };
  fields: RenderableSection<RenderableApexField[] | GroupedMember<RenderableApexField>[]> & { isGrouped: boolean };
  properties: RenderableSection<RenderableApexField[] | GroupedMember<RenderableApexField>[]> & { isGrouped: boolean };
  innerClasses: RenderableSection<RenderableClass[]>;
  innerEnums: RenderableSection<RenderableEnum[]>;
  innerInterfaces: RenderableSection<RenderableInterface[]>;
};

type RenderableInterface = RenderableType & {
  type: 'interface';
  extends?: StringOrLink[];
  methods: RenderableSection<RenderableMethod[]>;
};

type RenderableEnum = RenderableType & {
  type: 'enum';
  values: RenderableSection<EnumValue[]>;
};

type RenderableTrigger = Omit<RenderableType, 'meta'> & {
  type: 'trigger';
  objectName: string;
  events: string[];
};

type RenderableLwc = Omit<RenderableType, 'meta'> & {
  type: 'lwc';
  exposed: boolean;
  description: string | undefined;
  targets: RenderableSection<string[]>;
  targetConfigs: RenderableSection<TargetConfigRenderable[]>;
};

type TargetConfigRenderable = {
  targetName: string;
  properties: {
    type: string;
    required: boolean;
    description: string | undefined;
    label: string;
    name: string;
  }[];
};

type RenderableCustomObject = Omit<RenderableType, 'meta'> & {
  apiName: string;
  type: 'customobject';
  hasFields: boolean;
  hasRecords: boolean;
  fields: RenderableSection<RenderableCustomField[]>;
  metadataRecords: RenderableSection<RenderableCustomMetadata[]>;
  publishBehavior: string | null;
};

type RenderableCustomField = {
  headingLevel: number;
  heading: string;
  apiName: string;
  description: RenderableContent[];
  pickListValues?: RenderableSection<string[]>;
  type: 'field';
  fieldType?: string | null;
  required: boolean;
  complianceGroup: string | null;
  securityClassification: string | null;
  inlineHelpText: string | null;
};

type RenderableCustomMetadata = {
  headingLevel: number;
  heading: string;
  apiName: string;
  type: 'metadata';
  label: string;
  protected: boolean;
};

type Renderable = (
  | RenderableClass
  | RenderableInterface
  | RenderableEnum
  | RenderableCustomObject
  | RenderableTrigger
  | RenderableLwc
) & {
  filePath: string | undefined;
};

type Generators = 'markdown' | 'openapi' | 'changelog';

type LinkingStrategy =
  // Links will be generated using relative paths.
  | 'relative'
  // No links will be generated.
  // If the reference is found, the display name will be used.
  // Otherwise, the name
  // of the reference itself will be used.
  | 'no-link'
  // No logic will be applied, the reference path will be used as is.
  | 'none';

type MacroSourceMetadata = {
  type: 'apex' | 'customobject' | 'customfield' | 'custommetadata' | 'trigger' | 'lwc';
  name: string;
  filePath: string;
};

type MacroFunction = (metadata: MacroSourceMetadata) => string;

type CliConfigurableMarkdownConfig = {
  sourceDir?: string | string[];
  useSfdxProjectJson?: boolean;
  sfdxProjectPath?: string;
  targetDir: string;
  scope: string[];
  customObjectVisibility: string[];
  namespace?: string;
  defaultGroupName: string;
  customObjectsGroupName: string;
  triggersGroupName: string;
  lwcGroupName: string;
  sortAlphabetically: boolean;
  includeMetadata: boolean;
  linkingStrategy: LinkingStrategy;
  referenceGuideTitle: string;
  includeFieldSecurityMetadata: boolean;
  includeInlineHelpTextMetadata: boolean;
  experimentalLwcSupport: boolean;
  parallelReflection: boolean;
  parallelReflectionMaxWorkers?: number;
};

type UserDefinedMarkdownConfig = {
  targetGenerator: 'markdown';
  excludeTags: string[];
  exclude: string[];
  translations?: UserTranslations['markdown'];
} & CliConfigurableMarkdownConfig &
  Partial<MarkdownConfigurableHooks>;

type UserDefinedOpenApiConfig = {
  targetGenerator: 'openapi';
  sourceDir?: string | string[];
  useSfdxProjectJson?: boolean;
  sfdxProjectPath?: string;
  targetDir: string;
  fileName: string;
  namespace?: string;
  title: string;
  apiVersion: string;
  exclude: string[];
  parallelReflection: boolean;
  parallelReflectionMaxWorkers?: number;
};

type UserDefinedChangelogConfig = {
  targetGenerator: 'changelog';
  previousVersionDir?: string | string[];
  currentVersionDir?: string | string[];
  targetDir: string;
  fileName: string;
  scope: string[];
  customObjectVisibility: string[];
  exclude: string[];
  skipIfNoChanges: boolean;
  translations?: UserTranslations['changelog'];
  parallelReflection: boolean;
  parallelReflectionMaxWorkers?: number;
} & Partial<ChangelogConfigurableHooks>;

type UserDefinedConfig = UserDefinedMarkdownConfig | UserDefinedOpenApiConfig | UserDefinedChangelogConfig;

type MetadataTypes =
  | 'interface'
  | 'class'
  | 'enum'
  | 'customobject'
  | 'customfield'
  | 'custommetadata'
  | 'trigger'
  | 'lwc';

type SourceFileMetadata = {
  filePath: string;
  name: string;
  type: MetadataTypes;
};

// External metadata is metadata that does not live directly in the source code, and thus we don't
// have a file path for it.
// This is metadata derived from other information.
// For example, for an "extension"
// field that extends a Salesforce object or object in a different package, we want to capture the parent
// object, even if the file for that object was not parsed.
type ExternalMetadata = {
  name: string;
  type: MetadataTypes;
};

type DocPageReference = {
  source: SourceFileMetadata | ExternalMetadata;
  // The name under which the type should be displayed in the documentation.
  // By default, this will match the source.name, but it can be configured by the user.
  displayName: string;
  // The location where the file will be written.
  outputDocPath: string;
  // The path to the file relative to the documentation root directory. This is used when linking to the file.
  // Usually the value will be the same as outputDocPath. However, some site generators may have a different way of
  // organizing the files, so this allows for the flexibility of having a path from linking that is different from
  // the path where the file is written.
  referencePath: string;
};

type Frontmatter = string | Record<string, unknown> | null;

type ReferenceGuidePageData = {
  frontmatter: Frontmatter;
  content: string;
  outputDocPath: string;
};

type DocPageData = {
  source: SourceFileMetadata | ExternalMetadata;
  group: string | null;
  outputDocPath: string;
  frontmatter: Frontmatter;
  content: string;
  type: 'class' | 'interface' | 'enum' | 'customobject' | 'trigger' | 'lwc';
};

type FileChange = {
  name: string;
  fileType: 'apex' | 'customobject';
  changeType: 'added' | 'removed' | 'changed';
  changes?: {
    addedMethods?: string[];
    removedMethods?: string[];
    addedFields?: string[];
    removedFields?: string[];
    addedProperties?: string[];
    removedProperties?: string[];
    addedCustomFields?: string[];
    removedCustomFields?: string[];
    addedSubtypes?: string[];
    removedSubtypes?: string[];
    addedEnumValues?: string[];
    removedEnumValues?: string[];
  };
};

type SourceChangelog = {
  fileChanges: FileChange[];
};

type ChangeLogPageData = {
  source: SourceChangelog;
  frontmatter: Frontmatter;
  content: string;
  outputDocPath: string;
};

/**
 * Represents a file to be skipped.
 */
type Skip = {
  readonly _tag: 'Skip';
};

// CONFIGURABLE HOOKS

/**
 * Template configuration for customizing markdown output.
 */
type TemplateConfig = {
  class?: string | ((renderable: RenderableClass, helpers: TemplateHelpers) => string);
  interface?: string | ((renderable: RenderableInterface, helpers: TemplateHelpers) => string);
  enum?: string | ((renderable: RenderableEnum, helpers: TemplateHelpers) => string);
  trigger?: string | ((renderable: RenderableTrigger, helpers: TemplateHelpers) => string);
  lwc?: string | ((renderable: RenderableLwc, helpers: TemplateHelpers) => string);
  customObject?: string | ((renderable: RenderableCustomObject, helpers: TemplateHelpers) => string);
  referenceGuide?: string | ((data: ReferenceGuideData, helpers: TemplateHelpers) => string);
};

/**
 * Template helpers for consistent rendering.
 */
type TemplateHelpers = {
  link: (source: StringOrLink) => string;
  code: (codeBlock: CodeBlock) => string;
  renderContent: (content?: RenderableContent[]) => string;
  heading: (level: number, text: string) => string;
  inlineCode: (text: string) => string;
  eq: (a: unknown, b: unknown) => boolean;
  add: (a: number, b: number) => number;
  lookup: (array: unknown[], index: number) => unknown;
  parseJSON: (jsonString: string) => unknown | null;
  startsWith: (str: string, prefix: string) => boolean;
  substring: (str: string, start: number, length?: number) => string;
  splitAndCapitalize: (text: string) => string;
};

/**
 * Data structure passed to reference guide template functions.
 */
type ReferenceGuideData = {
  referenceGuideTitle: string;
  references: Record<string, ReferenceGuideReference[]>;
};

/**
 * The configurable hooks that can be used to modify the output of the Markdown generator.
 */
type MarkdownConfigurableHooks = {
  macros: Record<string, MacroFunction>;
  transformReferenceGuide: TransformReferenceGuide;
  transformDocs: TransformDocs;
  transformDocPage: TransformDocPage;
  transformReference: TransformReference;
  templates?: TemplateConfig;
};

type ConfigurableDocPageReference = Omit<DocPageReference, 'source'>;

type ConfigurableDocPageData = Omit<DocPageData, 'source' | 'outputDocPath'>;

/**
 * Allows changing where the files are written to.
 */
type TransformReference = (
  reference: DocPageReference,
) => Partial<ConfigurableDocPageReference> | Promise<ConfigurableDocPageReference>;

/**
 * Allows changing the frontmatter and content of the reference guide, or even if creating a reference
 * guide will be skipped altogether.
 */
type TransformReferenceGuide = (
  referenceGuide: ReferenceGuidePageData,
) => Partial<ReferenceGuidePageData> | Skip | Promise<Partial<ReferenceGuidePageData> | Skip>;

/**
 * The main purpose if for allowing for doc pages to be skipped, but it can also be used to change the frontmatter
 * and content of the doc pages.
 */
type TransformDocs = (docs: DocPageData[]) => DocPageData[] | Promise<DocPageData[]>;

/**
 * Allows changing the frontmatter and content of the doc pages.
 */
type TransformDocPage = (
  doc: DocPageData,
) => Partial<ConfigurableDocPageData> | Promise<Partial<ConfigurableDocPageData>>;

type ChangelogConfigurableHooks = {
  transformChangeLogPage: TransformChangelogPage;
};

type TransformChangelogPage = (
  page: ChangeLogPageData,
) => Partial<ChangeLogPageData> | Promise<Partial<ChangeLogPageData>>;

/**
 * Represents a file to be skipped.
 */
declare function skip(): Skip;

/**
 * Get all template helpers as an object matching TemplateHelpers type.
 */
declare const templateHelpers: TemplateHelpers;

type CallableConfig = Partial<UserDefinedConfig> & {
    sourceDir: string;
    targetGenerator: Generators;
};
/**
 * Processes the documentation generation, similar to the main function in the CLI.
 * @param config The configuration to use.
 */
declare function process(config: CallableConfig): Promise<void>;

type ConfigurableMarkdownConfig = Omit<Partial<UserDefinedMarkdownConfig>, 'targetGenerator'>;
/**
 * Helper function to define a configuration to generate Markdown documentation.
 * @param config The configuration to use.
 */
declare function defineMarkdownConfig(config: ConfigurableMarkdownConfig): Partial<UserDefinedMarkdownConfig>;
type ConfigurableOpenApiConfig = Omit<Partial<UserDefinedOpenApiConfig>, 'targetGenerator'>;
/**
 * Helper function to define a configuration to generate OpenAPI documentation.
 * @param config The configuration to use.
 */
declare function defineOpenApiConfig(config: ConfigurableOpenApiConfig): Partial<UserDefinedOpenApiConfig>;
type ConfigurableChangelogConfig = Omit<Partial<UserDefinedChangelogConfig>, 'targetGenerator'>;
/**
 * Helper function to define a configuration to generate a changelog.
 * @param config The configuration to use.
 */
declare function defineChangelogConfig(config: ConfigurableChangelogConfig): Partial<UserDefinedChangelogConfig>;

export { defineChangelogConfig, defineMarkdownConfig, defineOpenApiConfig, process, skip, templateHelpers };
export type { ChangeLogPageData, ChangelogConfigurableHooks, CodeBlock, ConfigurableChangelogConfig, ConfigurableDocPageData, ConfigurableDocPageReference, ConfigurableMarkdownConfig, ConfigurableOpenApiConfig, DocPageData, DocPageReference, GroupedMember, Link, MacroFunction, MacroSourceMetadata, MarkdownConfigurableHooks, ReferenceGuideData, ReferenceGuidePageData, ReferenceGuideReference, Renderable, RenderableApexField, RenderableClass, RenderableConstructor, RenderableContent, RenderableCustomObject, RenderableEnum, RenderableInterface, RenderableLwc, RenderableMethod, RenderableMethodParameter, RenderableSection, RenderableTrigger, Skip, SourceChangelog, StringOrLink, TemplateConfig, TemplateHelpers, TransformChangelogPage, TransformDocPage, TransformDocs, TransformReference, TransformReferenceGuide, Translations, TypeSource, UserTranslations };
