const axios = require('axios')
const { getRuntimeConfig } = require('./RuntimeConfig')

async function getPaymentConfig() {
    return getRuntimeConfig('pay')
}

function normalizePayBaseUrl(url) {
    return String(url || '').trim().replace(/\/+$/, '')
}

async function buildPaymentApiUrl(act, params = {}) {
    const paymentConfig = await getPaymentConfig()
    const baseUrl = normalizePayBaseUrl(paymentConfig.url)
    if (!baseUrl) {
        throw new Error('支付配置错误')
    }

    const url = new URL(`${baseUrl}/api.php`)
    url.searchParams.set('act', act)
    for (const [key, value] of Object.entries(params)) {
        if (value === undefined || value === null || value === '') continue
        url.searchParams.set(key, String(value))
    }
    return url.toString()
}

function parsePaymentResponseBody(data) {
    if (data && typeof data === 'object') return data
    if (typeof data !== 'string') return null
    const text = data.trim()
    if (!text) return null
    try {
        return JSON.parse(text)
    } catch (_) {
        return null
    }
}

function getAxiosPaymentOptions(extra = {}) {
    return {
        timeout: 15000,
        maxRedirects: 5,
        proxy: false,
        validateStatus: (status) => status >= 200 && status < 500,
        ...extra
    }
}

function formatPaymentHttpError(error, fallbackMessage) {
    if (error?.code === 'ECONNABORTED') {
        return '支付平台响应超时，请稍后重试'
    }
    if (error?.code === 'ERR_FR_TOO_MANY_REDIRECTS') {
        return '支付平台重定向异常，请检查 pay.url 配置或关闭系统代理后重试'
    }
    const status = Number(error?.response?.status || 0)
    const parsed = parsePaymentResponseBody(error?.response?.data)
    if (parsed?.msg) return String(parsed.msg)
    if (status === 503) return '支付平台暂时不可用，请稍后重试'
    if (status >= 500) return `支付平台异常(${status})，请稍后重试`
    return fallbackMessage || error?.message || '支付平台请求失败'
}

async function queryPaymentOrder(orderId, logger) {
    const paymentConfig = await getPaymentConfig()
    if (!paymentConfig.pid || !paymentConfig.url || !paymentConfig.key) {
        throw new Error('支付配置错误')
    }

    const queryUrl = await buildPaymentApiUrl('order', {
        pid: paymentConfig.pid,
        key: paymentConfig.key,
        out_trade_no: orderId
    })

    let response
    try {
        response = await axios.get(queryUrl, getAxiosPaymentOptions())
    } catch (error) {
        const message = formatPaymentHttpError(error, '查询支付状态失败')
        logger?.warn?.(`查询支付状态失败，订单号：${orderId}，URL：${queryUrl}，原因：${message}`)
        throw new Error(message)
    }

    const result = parsePaymentResponseBody(response.data)
    if (!result) {
        logger?.warn?.(`支付平台返回非 JSON，订单号：${orderId}，HTTP ${response.status}`)
        throw new Error('支付平台响应异常')
    }

    return result
}

function formatPaymentRefundError(response, fallbackMessage) {
    return formatPaymentHttpError({ response }, fallbackMessage || '支付平台退款失败')
}

function isRefundResponseSuccess(result) {
    if (!result || typeof result !== 'object') return false
    const code = Number(result.code)
    // 标准易支付：code=1；部分平台（如 yaolipay）：code=0 且带 refund_no
    if (code === 1) return true
    if (code === 0 && result.refund_no) return true
    return false
}

async function requestPaymentRefund({ orderId, tradeNo, money, logger }) {
    const paymentConfig = await getPaymentConfig()
    if (!paymentConfig.url || !paymentConfig.pid || !paymentConfig.key) {
        throw new Error('支付配置错误')
    }

    const refundUrl = await buildPaymentApiUrl('refund')
    const params = new URLSearchParams()
    params.append('pid', String(paymentConfig.pid))
    params.append('key', paymentConfig.key)
    if (tradeNo) {
        params.append('trade_no', tradeNo)
    } else {
        params.append('out_trade_no', orderId)
    }
    params.append('money', String(money))

    let response
    try {
        response = await axios.post(
            refundUrl,
            params.toString(),
            getAxiosPaymentOptions({
                timeout: 30000,
                headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                validateStatus: () => true
            })
        )
    } catch (error) {
        logger?.error?.(`易支付退款请求失败 订单号：${orderId}：${error.stack || error}`)
        throw new Error(formatPaymentHttpError(error, '无法连接支付平台，请稍后重试'))
    }

    const result = parsePaymentResponseBody(response.data)
    logger?.info?.(`易支付退款响应 订单号：${orderId}，HTTP ${response.status}，结果：${JSON.stringify(result ?? response.data)}`)

    if (response.status >= 400) {
        throw new Error(formatPaymentRefundError(response, '支付平台退款失败'))
    }

    if (!isRefundResponseSuccess(result)) {
        throw new Error(result?.msg || '支付平台退款失败')
    }

    return result
}

module.exports = {
    getPaymentConfig,
    normalizePayBaseUrl,
    buildPaymentApiUrl,
    getAxiosPaymentOptions,
    formatPaymentHttpError,
    formatPaymentRefundError,
    parsePaymentResponseBody,
    isRefundResponseSuccess,
    queryPaymentOrder,
    requestPaymentRefund
}
