import type { ESLintPluginRuleModule } from '@typescript-eslint/eslint-plugin/use-at-your-own-risk/rules';
import type * as unist from 'unist';

import { fromMarkdown } from 'mdast-util-from-markdown';

import type { VFileWithStem } from '../utils/rules';

import { findHeadingIndex } from '../utils/rules';

export interface RequiredHeadingIndices {
  howToUse: number;
  options: number;
  whenNotToUseIt: number;
}

// The first two may be autogenerated.
// Inserting one heading requires shifting all following ones.
export const requiredHeadingNames = [
  'How to Use',
  'Options',
  'When Not To Use It',
  'Related To',
] as const;

export type HeadingName = (typeof requiredHeadingNames)[number];

export class RuleDocsPage {
  #children: unist.Node[];
  #file: Readonly<VFileWithStem>;
  #headingIndices: RequiredHeadingIndices;
  #rule: Readonly<ESLintPluginRuleModule>;

  constructor(
    children: unist.Node[],
    file: Readonly<VFileWithStem>,
    rule: Readonly<ESLintPluginRuleModule>,
  ) {
    this.#children = children;
    this.#file = file;
    this.#headingIndices = this.#recreateHeadingIndices();
    this.#rule = rule;
  }

  #recreateHeadingIndices(): RequiredHeadingIndices {
    return {
      howToUse: findHeadingIndex(this.#children, 2, requiredHeadingNames[0]),
      options: findHeadingIndex(this.#children, 2, requiredHeadingNames[1]),
      whenNotToUseIt: findHeadingIndex(
        this.#children,
        2,
        requiredHeadingNames[2],
      ),
    };
  }

  spliceChildren(
    start: number,
    deleteCount: number,
    ...items: (string | unist.Node)[]
  ): void {
    this.#children.splice(
      start,
      deleteCount,
      ...items.map(item =>
        typeof item === 'string' ? fromMarkdown(item) : item,
      ),
    );
    this.#headingIndices = this.#recreateHeadingIndices();
  }

  get children(): readonly unist.Node[] {
    return this.#children;
  }

  get file(): Readonly<VFileWithStem> {
    return this.#file;
  }

  get headingIndices(): Readonly<RequiredHeadingIndices> {
    return this.#headingIndices;
  }

  get rule(): Readonly<ESLintPluginRuleModule> {
    return this.#rule;
  }
}
