import type {
  Callback,
  ElMessageBoxOptions,
  IElMessageBox,
  LoadingInstance,
  LoadingOptions,
  Message,
  MessageBoxData,
  MessageHandler,
  MessageParams,
} from 'element-plus';
import { playPromptTone } from '@/utils/prompt-tone';
import type { AppContext } from 'vue';
declare const ElMessage: Message;
declare const ElLoading: { service: { (options?: LoadingOptions, context?: AppContext | null): LoadingInstance; _context: AppContext | null } };
declare const ElMessageBox: IElMessageBox;

/**
 * toast弹出框
 */
export const Toast = {
  _show: (message: string, type: 'error' | 'info' | 'success' | 'warning', duration = 3000): MessageHandler => {
    return ElMessage({ showClose: true, grouping: true, message, type, duration });
  },
  show: (obj: MessageParams): MessageHandler => ElMessage(obj),
  info: (message: string, duration?: number) => Toast._show(message, 'info', duration),
  success: (message: string, duration?: number) => Toast._show(message, 'success', duration),
  warning: (message: string, duration?: number) => Toast._show(message, 'warning', duration),
  error: (message: string, duration?: number) => Toast._show(message, 'error', duration),
};

/**
 * 全屏加载动画
 */
export const FullLoading = {
  loadingInstance: null as { [key: string]: unknown; close: () => void } | null,
  show(text: string, options = {}) {
    this.loadingInstance = ElLoading.service({
      lock: true,
      fullscreen: true,
      ...options,
      text,
    });
  },
  hide() {
    this.loadingInstance && this.loadingInstance.close();
  },
};

export const MessageBox = {
  MessageBox: (op: ElMessageBoxOptions = {}): Promise<MessageBoxData> => {
    if ('callback' in op && typeof op.callback === 'function') {
      return ElMessageBox(getElMessageBoxOptions(op));
    } else {
      try {
        return ElMessageBox(getElMessageBoxOptions(op));
      } catch (error: any) {
        return Promise.reject(error);
      } finally {
        !('beforeClose' in op) && playPromptTone();
      }
    }
  },
  async alert(message: string, title?: string, op: ElMessageBoxOptions = {}): Promise<MessageBoxData> {
    if ('callback' in op && typeof op.callback === 'function') {
      return ElMessageBox.alert(message, title, getElMessageBoxOptions(op));
    } else {
      try {
        const res = await ElMessageBox.alert(message, title, getElMessageBoxOptions(op));
        return Promise.resolve(res);
      } catch (error: any) {
        return Promise.reject(error);
      } finally {
        !('beforeClose' in op) && playPromptTone();
      }
    }
  },
  async confirm(message: string, title?: string, op: ElMessageBoxOptions = {}): Promise<MessageBoxData> {
    if ('callback' in op && typeof op.callback === 'function') {
      return ElMessageBox.confirm(message, title, getElMessageBoxOptions(op));
    } else {
      try {
        const res = await ElMessageBox.confirm(message, title, getElMessageBoxOptions(op));
        return Promise.resolve(res);
      } catch (error: any) {
        return Promise.reject(error);
      } finally {
        !('beforeClose' in op) && playPromptTone();
      }
    }
  },
  async prompt(message: string, title?: string, op: ElMessageBoxOptions = {}): Promise<MessageBoxData> {
    if ('callback' in op && typeof op.callback === 'function') {
      return ElMessageBox.prompt(message, title, getElMessageBoxOptions(op));
    } else {
      try {
        const res = await ElMessageBox.prompt(message, title, getElMessageBoxOptions(op));
        return Promise.resolve(res);
      } catch (error: any) {
        return Promise.reject(error);
      } finally {
        !('beforeClose' in op) && playPromptTone();
      }
    }
  },
};

/**
 * 得到参数
 */
function getElMessageBoxOptions(op: ElMessageBoxOptions = {}) {
  const newOp = { ...op };

  if ('beforeClose' in op && typeof op.beforeClose === 'function') {
    newOp.beforeClose = (...args: Parameters<NonNullable<ElMessageBoxOptions['beforeClose']>>) => {
      playPromptTone();
      op?.beforeClose?.(...args);
    };
  }

  if ('callback' in op && typeof op.callback === 'function') {
    newOp.callback = (...args: Parameters<Callback>) => {
      !('beforeClose' in op) && playPromptTone();
      // @ts-expect-error: Unreachable code error
      op?.callback?.(...args);
    };
  }
  return newOp;
}
