import type { Editor } from '@tiptap/core';
import type { MediaItem, MediaViewFileType } from '@features/media/types';
import { buildMediaBlockContent } from '../../mediaBlockContent';

const isImageMedia = (item: MediaItem): boolean => item.media_type === 'image' || item.media_type === 'svg';

/**
 * 挿入対象を枠の種別 (accept) に従い、選択順を保って選別する。
 * - 'image' (画像ブロックの枠): 画像 (image/svg) かつ表示用サムネイル (media_thumbnail) を持つものだけ
 * - 'file' (ファイルブロックの枠): 画像以外のファイルだけ
 * - 'all' (エディタ本文への直接ドロップ): 画像はサムネイル必須・ファイルは全件 (混在可)
 *
 * これにより、画像枠にファイル・ファイル枠に画像が紛れても、枠の種別に合うものだけが挿入される。
 */
export const selectInsertableMedia = (items: MediaItem[], accept: MediaViewFileType): MediaItem[] =>
  items.filter((item) => {
    if (accept === 'image') {
      return isImageMedia(item) && Boolean(item.media_thumbnail);
    }
    if (accept === 'file') {
      return !isImageMedia(item);
    }
    return isImageMedia(item) ? Boolean(item.media_thumbnail) : true;
  });

/**
 * imageBlock 新規挿入時の拡大表示デフォルト値を、ImageBlock 拡張の設定から取得する。
 * 設定が取れない場合は現行動作 (拡大表示オン = noLightbox 'true') を維持する。
 */
const getImageDefaultNoLightbox = (editor: Editor): string => {
  const extension = editor.extensionManager.extensions.find((ext) => ext.name === 'imageBlock');
  const getter = extension?.options?.getImageDefaultLightbox;
  return typeof getter === 'function' && getter() ? 'false' : 'true';
};

/**
 * 選択メディアを枠の種別 (accept) で絞り込み、media_type で画像/ファイルブロックに振り分けて、
 * プレースホルダ (MediaUpload ノード) の range を一括置換する。insertContentAt による一括置換のため、
 * 対象が複数あっても 1 回の挿入で選択順に生成され、プレースホルダも確実に消える。
 *
 * @returns 挿入したブロック数 (挿入対象が無ければ 0、このとき editor は操作しない)
 */
export const insertMediaBlocks = (
  editor: Editor,
  items: MediaItem[],
  accept: MediaViewFileType,
  className: string,
  range: { from: number; to: number }
): number => {
  const targets = selectInsertableMedia(items, accept);
  if (targets.length === 0) {
    return 0;
  }
  const noLightbox = getImageDefaultNoLightbox(editor);
  const contents = targets.map((item) => buildMediaBlockContent(item, className, noLightbox));
  editor.chain().insertContentAt(range, contents).focus().run();
  return targets.length;
};
