import { useAuth } from '@/composables/useAuth'

export interface ApiResponse<T = unknown> {
  code: number
  message: string
  result: T
}

const API_BASE = import.meta.env.VITE_API_BASE || 'http://127.0.0.1:8081/api'
export const UPLOAD_BASE = import.meta.env.VITE_UPLOAD_BASE || 'http://127.0.0.1:8081'

/**
 * 媒体地址：已是完整链接 / data: 则原样返回；否则拼上传域名（后端 /uploads 等）。
 */
export function getImageUrl(url?: string | null): string {
  if (!url) return ''
  const raw = String(url).trim()
  if (!raw) return ''
  if (/^https?:\/\//i.test(raw) || raw.startsWith('data:') || raw.startsWith('//')) return raw
  if (raw.startsWith('/')) return `${UPLOAD_BASE}${raw}`
  return `${UPLOAD_BASE}/${raw}`
}

/** 兼容旧名，与 getImageUrl 同逻辑 */
export const resolveMediaUrl = getImageUrl

/**
 * 重写 HTML 中相对路径的 src/href（如 /uploads/...），供 mp-html / rich-text 使用。
 * 已是 http(s) / data: / 协议相对 // 的不改。
 */
export function rewriteHtmlMediaUrls(html?: string | null): string {
  if (!html) return ''
  return String(html).replace(
    /\b(src|href)\s*=\s*(["'])(\/[^"'>\s]*)\2/gi,
    (_m, attr: string, quote: string, path: string) => {
      // 协议相对 //cdn... 不要当成本地路径
      if (path.startsWith('//')) return `${attr}=${quote}${path}${quote}`
      return `${attr}=${quote}${getImageUrl(path)}${quote}`
    },
  )
}

function joinUrl(path: string): string {
  if (/^https?:\/\//i.test(path)) return path
  const base = API_BASE.replace(/\/$/, '')
  const p = path.startsWith('/') ? path : `/${path}`
  if (p.startsWith('/api/')) return `${UPLOAD_BASE}${p}`
  return `${base}${p}`
}

/**
 * GET 查询参数清洗：去掉 undefined/null/''，避免 uni.request 把 undefined 序列化成字面量 "undefined"。
 */
function omitEmptyQueryParams(data?: Record<string, unknown>) {
  if (!data) return undefined
  const entries = Object.entries(data).filter(([, v]) => v !== undefined && v !== null && v !== '')
  if (!entries.length) return undefined
  return Object.fromEntries(entries)
}

type RequestOpts = {
  method?: UniApp.RequestOptions['method']
  data?: UniApp.RequestOptions['data']
  header?: Record<string, string>
  auth?: boolean
  skipSessionExpired?: boolean
}

export async function request<T>(path: string, options: RequestOpts = {}): Promise<T> {
  const { auth = false, skipSessionExpired = false, header = {}, method = 'GET', data } = options
  const headers: Record<string, string> = {
    'Content-Type': 'application/json',
    ...header,
  }

  if (auth) {
    const { getToken } = useAuth()
    const token = getToken()
    if (token) headers.Authorization = `Bearer ${token}`
  }

  /** GET 走清洗后的 query；其它方法保持原 body */
  const payload = method === 'GET'
    ? omitEmptyQueryParams(data as Record<string, unknown> | undefined)
    : data

  return new Promise((resolve, reject) => {
    uni.request({
      url: joinUrl(path),
      method,
      data: payload,
      header: headers,
      success: (res) => {
        const body = res.data as ApiResponse<T>
        if (!body || typeof body !== 'object' || !('code' in body)) {
          reject(new Error('响应解析失败'))
          return
        }
        if (body.code === 401 && !skipSessionExpired) {
          const { handleSessionExpired } = useAuth()
          handleSessionExpired()
          reject(new Error(body.message || '登录已过期，请重新登录'))
          return
        }
        if (body.code !== 200) {
          reject(new Error(body.message || '请求失败'))
          return
        }
        resolve(body.result)
      },
      fail: (err) => reject(new Error(err.errMsg || '网络错误')),
    })
  })
}

export function get<T>(path: string, data?: Record<string, unknown>, auth = false) {
  return request<T>(path, { method: 'GET', data, auth })
}

export function post<T>(path: string, data?: unknown, auth = false) {
  return request<T>(path, { method: 'POST', data: data as UniApp.RequestOptions['data'], auth })
}

export function put<T>(path: string, data?: unknown, auth = false) {
  return request<T>(path, { method: 'PUT', data: data as UniApp.RequestOptions['data'], auth })
}

export function del<T>(path: string, auth = true) {
  return request<T>(path, { method: 'DELETE', auth })
}

/** PATCH 请求（文章发布状态等） */
export function patch<T>(path: string, data?: unknown, auth = false) {
  return request<T>(path, {
    method: 'PATCH' as UniApp.RequestOptions['method'],
    data: data as UniApp.RequestOptions['data'],
    auth,
  })
}

/**
 * 直传文件到后台附件接口。
 * uni.uploadFile 不走 JSON Content-Type，需单独拼 Authorization。
 */
export function uploadFile<T = { fileUrl?: string, url?: string, id?: number }>(
  path: string,
  filePath: string,
  formData: Record<string, string> = {},
  name = 'file',
): Promise<T> {
  const { getToken } = useAuth()
  const token = getToken()
  const header: Record<string, string> = {}
  if (token) header.Authorization = `Bearer ${token}`
  return new Promise((resolve, reject) => {
    uni.uploadFile({
      url: joinUrl(path),
      filePath,
      name,
      formData,
      header,
      success: (res) => {
        try {
          const body = JSON.parse(res.data) as ApiResponse<T>
          if (body.code === 401) {
            const { handleSessionExpired } = useAuth()
            handleSessionExpired()
            reject(new Error(body.message || '登录已过期，请重新登录'))
            return
          }
          if (body.code !== 200) {
            reject(new Error(body.message || '上传失败'))
            return
          }
          resolve(body.result)
        }
        catch {
          reject(new Error('上传响应解析失败'))
        }
      },
      fail: (err) => reject(new Error(err.errMsg || '上传失败')),
    })
  })
}
