/**
 * MX 原生桥接 API 模块
 *
 * 用于在敏行混合应用中与原生 Android/iOS 通信
 * 提供原生能力调用：UI 控制、用户信息、选人组件、原生 HTTP 请求
 */

// ============================================================
// 类型定义
// ============================================================

/** 原生 AJAX 请求参数 */
interface MXAjaxParams {
  type: 'GET' | 'POST' | 'PUT' | 'DELETE'
  url: string
  data?: unknown
  async?: boolean
  success?: (data: string, status: number, xhr: unknown) => void
  error?: (data: unknown, status: number, xhr: unknown) => void
}

/** 原生 AJAX 响应 */
export interface MXAjaxResponse<T = unknown> {
  data: T
  status: number
}

/** 用户信息 */
export interface MXUser {
  id: string
  name: string
  token: string
  [key: string]: unknown
}

/** 选人组件配置 */
export interface MXSelectUsersOptions {
  enableSelectDept?: boolean
  canSelectSelf?: boolean
}

/** MXApi 回调函数集合 */
interface MXApiCallbacks {
  ready?: () => void
  error?: (message: string, namespace: string, api: string) => void
  beforeApply?: (namespace: string, api: string, args: unknown[]) => void
}

/** 原生接口命名空间 */
type MXNamespace = 'MXCommon' | 'MXWebui' | 'MXContacts'

// ============================================================
// 声明全局原生接口
// ============================================================

declare global {
  interface Window {
    MXCommon?: {
      getCurrentUser: (callback: (user: MXUser) => void) => void
      getEncryptString: (callback: (secret: string) => void) => void
      ajax: (params: MXAjaxParams) => void
    }
    MXWebui?: {
      hideWebViewTitle: () => void
      showOptionMenu: () => void
      setCustomHeaderMenu: (...args: unknown[]) => void
    }
    MXContacts?: {
      selectUsers: (
        callback: (users: MXUser[]) => void,
        options: MXSelectUsersOptions
      ) => void
    }
  }
}

// ============================================================
// 核心实现
// ============================================================

/**
 * MXApi 工厂函数
 *
 * 创建原生 API 调用器，处理设备就绪状态和任务队列。
 * 在 Cordova/Capacitor 环境中，原生接口在 deviceready 事件触发后才可用。
 */
function MXApi(callbacks: MXApiCallbacks) {
  let deviceReady = false
  const taskQueue: Array<[MXNamespace, string, unknown[]]> = []

  document.addEventListener('deviceready', function deviceReadyHandler() {
    deviceReady = true

    // 执行队列中的所有待处理任务
    taskQueue.forEach((task) => {
      applyApi(...task)
    })

    callbacks.ready?.()
    document.removeEventListener('deviceready', deviceReadyHandler, false)
  }, false)

  /**
   * 核心函数：调用原生 API
   *
   * 通过 window[namespace][api] 的方式访问原生注入的方法
   */
  function applyApi(namespace: MXNamespace, api: string, args: unknown[]) {
    const nativeInterface = window[namespace] as Record<string, ((...args: unknown[]) => void) | undefined> | undefined

    if (nativeInterface && typeof nativeInterface[api] === 'function') {
      callbacks.beforeApply?.(namespace, api, args)
      nativeInterface[api]!(...args)
    } else if (!deviceReady) {
      // 设备未就绪，加入队列等待
      taskQueue.push([namespace, api, args])
    } else {
      const errorMsg = `该终端没有 ${namespace}.${api} 方法!`
      callbacks.error?.(errorMsg, namespace, api)
      throw new Error(errorMsg)
    }
  }

  return applyApi
}

// 创建全局调用器实例
const applyApi = MXApi({
  ready() {
    console.log('[MX] 设备就绪')
  },
  error(err) {
    console.error('[MX] 错误:', err)
  },
  beforeApply(namespace, api, args) {
    console.debug(`[MX] 调用 ${namespace}.${api}`, args)
  },
})

// 创建命名空间调用器（柯里化）
const makeApi =
  (namespace: MXNamespace) =>
  (api: string, ...args: unknown[]) =>
    applyApi(namespace, api, args)

const MXCommon = makeApi('MXCommon')
const MXWebui = makeApi('MXWebui')
const MXContacts = makeApi('MXContacts')

// ============================================================
// 导出的业务 API
// ============================================================

/** 隐藏 WebView 标题栏 */
export const hideWebViewTitle = (): void => MXWebui('hideWebViewTitle')

/** 显示右上角菜单按钮 */
export const showOptionMenu = (): void => MXWebui('showOptionMenu')

/** 设置自定义头部菜单 */
export const setCustomHeaderMenu = (...args: unknown[]): void =>
  MXWebui('setCustomHeaderMenu', ...args)

/** 获取当前登录用户信息 */
export const getCurrentUser = (): Promise<MXUser> =>
  new Promise((resolve) => {
    MXCommon('getCurrentUser', resolve)
  })

/** 从原生客户端获取加密密钥 */
export const getEncryptString = (): Promise<string> =>
  new Promise((resolve) => {
    MXCommon('getEncryptString', resolve)
  })

/** 打开原生选人组件 */
export const MXSelectUsers = (
  options: MXSelectUsersOptions = { enableSelectDept: false, canSelectSelf: true }
): Promise<MXUser[]> =>
  new Promise((resolve) => {
    MXContacts('selectUsers', (result: MXUser[]) => {
      resolve(result)
    }, options)
  })

/**
 * 原生 AJAX 请求
 *
 * 使用原生应用的 HTTP 客户端发起请求，绕过浏览器同源策略限制。
 */
export const ajax = <T = unknown>(params: Omit<MXAjaxParams, 'success' | 'error'>): Promise<MXAjaxResponse<T>> =>
  new Promise((resolve, reject) => {
    const requestParams: MXAjaxParams = {
      ...params,
      url: `${import.meta.env.VITE_API_BASE_URL || ''}${params.url}`,
      async: true,
      success(data, status) {
        resolve({ data: JSON.parse(data) as T, status })
      },
      error(data, status) {
        reject({ data, status })
      },
    }

    MXCommon('ajax', requestParams)
  })

/** 原生 GET 请求 */
export const ajaxGet = <T = unknown>(url: string, query?: Record<string, unknown>): Promise<MXAjaxResponse<T>> => {
  const queryString = query
    ? '?' + Object.entries(query)
        .filter(([, value]) => value !== undefined && value !== null)
        .map(([key, value]) => `${key}=${value}`)
        .join('&')
    : ''

  return ajax<T>({
    type: 'GET',
    url: `${url}${queryString}`,
  })
}

/** 原生 POST 请求 */
export const ajaxPost = <T = unknown>(url: string, data?: unknown): Promise<MXAjaxResponse<T>> =>
  ajax<T>({ type: 'POST', url, data })

/** 原生 PUT 请求 */
export const ajaxPut = <T = unknown>(url: string, data?: unknown): Promise<MXAjaxResponse<T>> =>
  ajax<T>({ type: 'PUT', url, data })

/** 原生 DELETE 请求 */
export const ajaxDelete = <T = unknown>(url: string, id: string): Promise<MXAjaxResponse<T>> =>
  ajax<T>({ type: 'DELETE', url: `${url}/${id}` })

/** 检测是否在原生环境 */
export const isNativeApp = (): boolean =>
  typeof window.MXCommon !== 'undefined'
