import { Boot } from '@wangeditor/editor';
import type { EditorInstance, EditorUploadProps } from './types';
import { ctrlEnterModule, markdownModule } from './module';
import { deleteVideoMenu, previewMenu } from './menus';

export function upload(this: EditorInstance, props: EditorUploadProps) {
  const accept = props.accept?.split(',').map((v) => v.trim()) ?? [];
  if (accept.includes('*/*')) accept.length = 0;

  const maxFileSize = props.maxFileSize;
  const minFileSize = props.minFileSize;

  return {
    customUpload: async (file: File, insertFn: (url: string, altOrPoster: string) => void) => {
      const isVideo = file.type.startsWith('video');
      const progress = (value: number, event?: { loaded: number; total: number }) => {
        this.showProgressBar(value);
        const total = event?.total ?? file.size;
        const loaded = event?.loaded ?? (value ? total : 0);
        this.emit('upload:progress', {
          key: `upload-${file.name}`,
          message: value ? `${file.name} 文件已上传：${value}%` : `${file.name} 文件：开始上传 `,
          description: `请等待上传完成在操作编辑器`,
          total,
          loaded,
          progress: value,
        });
      };
      const success = (data: { url: string; name?: string; poster?: string }) => {
        this.emit('upload:success', {
          key: `upload-${file.name}`,
          message: `${file.name} 文件：上传成功`,
          description: `请操作编辑器`,
          ...data,
        });
        this.alert(`上传成功`, 'success');
      };
      const failed = (error: { message: string }) => {
        this.emit('upload:failed', {
          key: `upload-${file.name}`,
          message: `${file.name} 文件：上传失败`,
          description: error.message,
        });
        this.alert(`上传失败(${error.message})`, 'error');
      };
      let off: any;
      try {
        if (props.onBeforeUpload) props.onBeforeUpload?.call(this, file, props);
        else {
          const type = file.type;
          if (/*type && */ accept.length && !(accept.includes(type) || accept.includes(type.split('/')[0] + '/*'))) {
            throw { message: `文件类型(${type || '未知'})不允许, 仅允许: ${accept.join('; ')}` };
          }

          const size = file.size;
          if (size && minFileSize && size < minFileSize) throw { message: `${file.name} 文件太小` };
          if (size && maxFileSize && size > maxFileSize) throw { message: `${file.name} 文件太大` };
        }
        const method = props.handle(file);
        off = method.onUpload((event) => {
          const decimal = 10 ** 2;
          const value = Math.floor((event.loaded * 100 * decimal) / event.total) / decimal;
          progress?.(Math.min(value, 99), event);
        });
        progress(0);
        const { url, name = file.name, poster = '' } = await method;
        insertFn(url, isVideo ? poster : name);
        progress(100);
        success({ url, name, poster });
      } catch (error: any) {
        failed(error);
      }
      off?.();
    },
  };
}

export function getResources(this: EditorInstance, type?: 'image' | 'video'): string[] {
  if (type === 'image') return this.getElemsByType('image').map((item: any) => item.src);
  if (type === 'video') return this.getElemsByType('video').flatMap((item: any) => [item.src, item.poster]);
  return [...this.getElemsByType('image'), ...this.getElemsByType('video')].flatMap((item: any) => [item.src, item.poster]).filter(Boolean);
}

let booted = false;
export function register() {
  if (booted) return;
  Boot.registerModule(markdownModule);
  // Boot.registerModule(ctrlEnterModule);
  Boot.registerMenu(previewMenu);
  Boot.registerMenu(deleteVideoMenu);
  booted = true;
}

export function isEditorInstance(instance: unknown): instance is EditorInstance {
  return instance != null && typeof instance === 'object' && typeof (instance as any)['getHtml'] === 'function';
}

export function getElement(parent: HTMLElement, selector: `#${string}` | `.${string}`): HTMLElement {
  let element = parent.querySelector<HTMLElement>(selector);
  if (!element) {
    element = document.createElement('div');
    if (selector.startsWith('#')) element.id = selector.slice(1);
    else if (selector.startsWith('.')) element.classList.add(selector.slice(1));
    parent.appendChild(element);
  }
  return element;
}
