import { getKuaishouIndustryConfig } from './config.js'
import { signKuaishouIndustryPayload, type SignMethod } from './crypto.js'
import { ensureKuaishouIndustryAccessToken } from './token-service.js'
import { logIntegration } from '../../../utils/logger.js'
import type { JsonObject } from '../../../types/json.js'
export type { JsonObject }

type KuaishouIndustryOpenApiCallInput = {
  apiMethod: string
  path: string
  bizParams: JsonObject
  httpMethod?: 'GET' | 'POST'
  sellerId?: string
  signMethod?: SignMethod
  onRequest?: (request: JsonObject) => void
  disableDefaultLog?: boolean
}

export type KuaishouIndustryOpenApiCallResult = {
  success: boolean
  response?: JsonObject
  error?: string
  request?: JsonObject
  durationMs?: number
  httpStatus?: number
  skippedReason?: 'disabled' | 'missing_access_token' | 'token_error'
  errorDetail?: JsonObject
}

const DEFAULT_KUAISHOU_OPEN_API = 'https://openapi.kwaixiaodian.com'

export async function requestKuaishouIndustryOpenApi(
  input: KuaishouIndustryOpenApiCallInput,
): Promise<KuaishouIndustryOpenApiCallResult> {
  let config = getKuaishouIndustryConfig()
  const apiLabel = formatKuaishouOpenApiLabel(input.apiMethod)

  if (!config.enabled) {
    logKuaishouOpenApi(input, `快手 OpenAPI 未启用，跳过 ${apiLabel}`, undefined)
    return { success: true, skippedReason: 'disabled' }
  }

  try {
    const tokenResult = await ensureKuaishouIndustryAccessToken({
      config,
      ...(input.sellerId ? { sellerId: input.sellerId } : {}),
    })
    config = {
      ...config,
      ...tokenResult.config,
      accessToken: tokenResult.accessToken,
    }
  } catch (error) {
    logKuaishouOpenApi(
      input,
      `快手 OpenAPI token 准备失败 ${apiLabel}`,
      resolveKuaishouOpenApiErrorDetail(error),
      'warn',
    )
    return {
      success: false,
      skippedReason: 'token_error',
      error: error instanceof Error ? error.message : String(error),
      errorDetail: resolveKuaishouOpenApiErrorDetail(error),
    }
  }

  if (!config.accessToken) {
    logKuaishouOpenApi(input, `快手 OpenAPI accessToken 缺失 ${apiLabel}`, undefined, 'warn')
    return {
      success: false,
      skippedReason: 'missing_access_token',
      error: 'accessToken 未配置',
    }
  }

  const signMethod = input.signMethod || 'MD5'
  const paramStr = JSON.stringify(input.bizParams)
  const signParams: JsonObject = {
    method: input.apiMethod,
    appkey: config.appKey,
    access_token: config.accessToken,
    version: config.version || '1',
    timestamp: Date.now(),
    signMethod,
    param: paramStr,
  }
  signParams.sign = signKuaishouIndustryPayload(signParams, signMethod, config)

  const body = new URLSearchParams()
  for (const [key, value] of Object.entries(signParams)) {
    body.append(key, String(value))
  }

  const httpMethod = input.httpMethod || 'POST'
  const url = `${resolveKuaishouOpenApiBaseUrl(config.baseUrl)}${normalizeOpenApiPath(input.path)}`
  const requestLog = buildKuaishouOpenApiRequestLog({
    url,
    signParams,
    bizParams: input.bizParams,
    httpMethod,
  })

  input.onRequest?.(requestLog)
  logKuaishouOpenApi(input, `发起快手 OpenAPI ${apiLabel}`, requestLog)

  try {
    const startedAt = Date.now()
    const res =
      httpMethod === 'GET'
        ? await fetch(`${url}?${body.toString()}`, { method: 'GET' })
        : await fetch(url, {
            method: 'POST',
            headers: { 'content-type': 'application/x-www-form-urlencoded' },
            body: body.toString(),
          })
    const text = await res.text()
    let json: JsonObject = {}
    try {
      json = JSON.parse(text)
    } catch {
      json = { raw: text }
    }

    const durationMs = Date.now() - startedAt
    const success = res.ok && Number(json.result) === 1
    logKuaishouOpenApi(
      input,
      success ? `快手 OpenAPI 调用成功 ${apiLabel}` : `快手 OpenAPI 调用失败 ${apiLabel}`,
      {
        durationMs,
        httpStatus: res.status,
        request: requestLog,
        response: json,
      },
      success ? 'info' : 'warn',
    )

    return {
      success,
      response: json,
      request: requestLog,
      durationMs,
      httpStatus: res.status,
    }
  } catch (error) {
    const errorDetail = resolveKuaishouOpenApiErrorDetail(error)
    logKuaishouOpenApi(
      input,
      `快手 OpenAPI 调用异常 ${apiLabel}`,
      {
        ...errorDetail,
        request: requestLog,
      },
      'warn',
    )
    return {
      success: false,
      error: error instanceof Error ? error.message : String(error),
      request: requestLog,
      errorDetail,
    }
  }
}

export function buildKuaishouOpenApiRequestLog({
  url,
  signParams,
  bizParams,
  httpMethod,
}: {
  url: string
  signParams: JsonObject
  bizParams: JsonObject
  httpMethod?: 'GET' | 'POST'
}): JsonObject {
  return {
    url,
    method: httpMethod || 'POST',
    contentType: 'application/x-www-form-urlencoded',
    apiName: resolveKuaishouOpenApiName(signParams.method),
    apiMethod: signParams.method,
    appkey: signParams.appkey,
    access_token: signParams.access_token,
    version: signParams.version,
    timestamp: signParams.timestamp,
    signMethod: signParams.signMethod,
    sign: signParams.sign,
    param: bizParams,
  }
}

export function resolveKuaishouOpenApiBaseUrl(value: unknown): string {
  return (
    String(value || DEFAULT_KUAISHOU_OPEN_API)
      .trim()
      .replace(/\/+$/, '') || DEFAULT_KUAISHOU_OPEN_API
  )
}

export function resolveKuaishouOpenApiErrorDetail(error: unknown): JsonObject {
  const detail: JsonObject = {
    error: error instanceof Error ? error.message : String(error),
  }
  const cause =
    error && typeof error === 'object' && 'cause' in error
      ? (error as { cause?: unknown }).cause
      : null
  if (!cause || typeof cause !== 'object') {
    return detail
  }

  const current = cause as Record<string, unknown>
  const fields: Array<[string, unknown]> = [
    ['causeMessage', current.message],
    ['causeCode', current.code],
    ['causeSyscall', current.syscall],
    ['causeHostname', current.hostname],
  ]
  for (const [key, value] of fields) {
    const text = String(value || '').trim()
    if (text) {
      detail[key] = text
    }
  }

  return detail
}

function normalizeOpenApiPath(value: unknown): string {
  const path = String(value || '').trim()
  if (!path) {
    return '/'
  }
  return path.startsWith('/') ? path : `/${path}`
}

function logKuaishouOpenApi(
  input: Pick<KuaishouIndustryOpenApiCallInput, 'apiMethod' | 'disableDefaultLog'>,
  message: string,
  detail?: JsonObject,
  level: 'info' | 'warn' | 'error' = 'info',
) {
  if (input.disableDefaultLog) {
    return
  }

  logIntegration('[kuaishou-industry/openapi]', message, detail, { level })
}

function formatKuaishouOpenApiLabel(method: unknown): string {
  const apiMethod = String(method || '').trim()
  const apiName = resolveKuaishouOpenApiName(apiMethod)
  return apiName ? `${apiName}(${apiMethod})` : apiMethod
}

function resolveKuaishouOpenApiName(method: unknown): string {
  const apiMethod = String(method || '').trim()
  const names: Record<string, string> = {
    'open.order.cursor.list': '获取订单列表v2',
    'open.seller.order.close': '关闭订单',
    'open.seller.order.fee.detail': '获取订单费用详情',
    'open.order.detail': '订单详情v2',
    'open.seller.order.refund.detail': '售后单详情',
    'open.seller.order.refund.fee.detail': '退款费用详情',
    'open.seller.order.refund.approve': '商家同意退款',
    'open.seller.order.refund.pcursor.list': '售后单列表',
    'open.seller.order.refund.disagree.refund': '商家不同意退款',
    'open.item.get': '获取商品详情',
    'open.item.new': '商品新增',
    'open.item.edit': '编辑商品',
    'integration.item.stock.deduct': '商品库存扣减',
    'integration.item.stock.query': '商品库存查询',
    'open.item.shelf.status.update': '商品上下架管理',
    'open.item.list.get': '查询商品列表',
    'open.shop.poi.getPoiDetailByOuterPoi': '通过图商 POI 获取快手 POI 详情',
    'integration.callback.virtual.eticket.send': '电子凭证发货回调',
    'integration.callback.virtual.eticket.consume': '电子凭证核销回调',
    'integration.callback.virtual.eticket.destroy': '电子凭证销毁回调',
    'integration.callback.virtual.eticket.reverse': '电子凭证冲正回调',
    'open.virtual.eticket.checkavailable': '检查电子凭证有效性',
    kwaishop_refund_addRefund: '新增退款单消息',
    kwaishop_refund_updateRefund: '退款单更新消息',
    kwaishop_aftersales_addRefund: '售后单新增消息',
    kwaishop_order_addOrder: '订单新增消息',
    kwaishop_order_statusChange: '订单状态变更消息',
    kwaishop_order_totalFeeChange: '订单费用变更消息',
    kwaishop_order_addNote: '订单备注消息',
    KwaishopVirtualEticketSendService: '快手电子凭证通知发货',
    KwaishopVirtualEticketQueryService: '电子凭证查询发码结果或券码状态',
    KwaishopDigitalETicketDestoryService: '电子凭证发起销毁',
    'integration.virtual.eticket.send': '电子凭证通知发码',
    'integration.virtual.eticket.query': '电子凭证查询发码结果或券码状态',
    'integration.virtual.eticket.destroy': '电子凭证发起销毁',
  }

  return names[apiMethod] || ''
}
