import type { EditorHost } from '@blockeditor/lit';
import type { BlockModel } from '@blockeditor/store';
import type { TemplateResult } from 'lit';

import type { AffineTextAttributes } from '../../../_common/inline/presets/affine-inline-specs.js';
import { isInsideBlockByFlavour } from '../../../_common/utils/index.js';
import { getInlineEditorByModel } from '../../../_common/utils/query.js';
import type { PageBlockComponent } from '../../../page-block/types.js';

export type AIMenuOptions = {
  /**
   * If return false, the ai menu will not show
   *
   * If return string, the ai menu will show and the string will be clear after the ai menu is activated
   */
  isTriggerKey: (e: KeyboardEvent) => false | string;
  menus: {
    name: string;
    items:
      | ((options: {
          pageElement: PageBlockComponent;
          model: BlockModel;
        }) => AIItem[])
      | AIItem[];
  }[];
};

export type AIItem = {
  name: string;
  /**
   * search alias
   */
  alias?: string[];
  /**
   * size 20x20
   */
  icon: TemplateResult<1>;
  suffix?: TemplateResult<1>;
  showWhen?: (model: BlockModel, pageElement: PageBlockComponent) => boolean;
  disabled?: boolean;
  action: ({
    pageElement,
    model,
  }: {
    pageElement: PageBlockComponent;
    model: BlockModel;
  }) => void | Promise<void>;
};

export type InternAIItem = AIItem & { groupName: string };

export function collectGroupNames(menuItem: InternAIItem[]) {
  return menuItem.reduce((acc, item) => {
    if (!acc.length || acc[acc.length - 1] !== item.groupName) {
      acc.push(item.groupName);
    }
    return acc;
  }, [] as string[]);
}

export function insertContent(
  editorHost: EditorHost,
  model: BlockModel,
  text: string,
  attributes?: AffineTextAttributes
) {
  if (!model.text) {
    throw new Error("Can't insert text! Text not found");
  }
  const inlineEditor = getInlineEditorByModel(editorHost, model);
  if (!inlineEditor) {
    throw new Error("Can't insert text! Inline editor not found");
  }
  const inlineRange = inlineEditor.getInlineRange();
  const index = inlineRange ? inlineRange.index : model.text.length;
  model.text.insert(text, index, attributes as Record<string, unknown>);
  // Update the caret to the end of the inserted text
  inlineEditor.setInlineRange({
    index: index + text.length,
    length: 0,
  });
}

export function formatDate(date: Date) {
  // yyyy-mm-dd
  const year = date.getFullYear();
  const month = (date.getMonth() + 1).toString().padStart(2, '0');
  const day = date.getDate().toString().padStart(2, '0');
  const strTime = `${year}-${month}-${day}`;
  return strTime;
}

export function insideDatabase(model: BlockModel) {
  return isInsideBlockByFlavour(model.page, model, 'affine:database');
}

export function insideDataView(model: BlockModel) {
  return isInsideBlockByFlavour(model.page, model, 'affine:data-view');
}

export function withRemoveEmptyLine(fn: AIItem['action']): AIItem['action'] {
  return async args => {
    await fn(args);
    const { model } = args;
    if (!model.text?.length) {
      model.page.deleteBlock(model);
    }
  };
}
