import { createHttpError } from '../../../utils/http.js'
import { assertKuaishouIndustryConfig } from './config.js'
import { asJsonObject, type JsonObject } from '../../../types/json.js'

export function normalizeIndustryString(value: unknown) {
  return String(value || '').trim()
}

export function normalizeSendCodePayload(raw: JsonObject = {}) {
  const param = parseParamField(raw)
  return {
    appKey: normalizeIndustryString(raw.appkey),
    version: normalizeIndustryString(raw.version),
    timestamp: normalizeIndustryTimestamp(raw.timestamp),
    signMethod: normalizeIndustryString(raw.signMethod || 'MD5'),
    sign: normalizeIndustryString(raw.sign),
    accessToken: normalizeIndustryString(raw.access_token),
    method: normalizeIndustryString(raw.method),
    paramRaw: normalizeIndustryString(raw.param),

    oid: normalizeIndustryString(param.oid),
    sellerId: normalizeIndustryString(param.sellerId),
    num: normalizeIndustryInteger(param.num),
    itemId: normalizeIndustryString(param.itemId),
    skuId: normalizeIndustryString(param.skuId),
    itemTitle: normalizeIndustryString(param.itemTitle),
    sendType: normalizeIndustryString(param.sendType) || 'VIRTUAL',
    eticketType: normalizeIndustryString(param.eticketType),
    token: normalizeIndustryString(param.token),
    certExpireType: normalizeIndustryInteger(param.certExpireType),
    certStartTime: normalizeIndustryLong(param.certStartTime),
    certEndTime: normalizeIndustryLong(param.certEndTime),
    certExpDays: normalizeIndustryInteger(param.certExpDays),
    certActualStartTime: normalizeIndustryLong(param.certActualStartTime),
    certActualEndTime: normalizeIndustryLong(param.certActualEndTime),
    expressCode: normalizeIndustryString(param.expressCode),
    expressNo: normalizeIndustryString(param.expressNo),
    ext: normalizeIndustryString(param.ext),
  }
}

export function normalizeDestroyCodePayload(raw: JsonObject = {}) {
  const param = parseParamField(raw)
  return {
    appKey: normalizeIndustryString(raw.appkey),
    version: normalizeIndustryString(raw.version),
    timestamp: normalizeIndustryTimestamp(raw.timestamp),
    signMethod: normalizeIndustryString(raw.signMethod || 'MD5'),
    sign: normalizeIndustryString(raw.sign),
    accessToken: normalizeIndustryString(raw.access_token),
    method: normalizeIndustryString(raw.method),
    paramRaw: normalizeIndustryString(raw.param),

    oid: normalizeIndustryString(param.oid),
    sellerId: normalizeIndustryString(param.sellerId),
    reason: normalizeIndustryString(param.reason),
    token: normalizeIndustryString(param.token),
    etickets: normalizeDestroyEtickets(param.etickets),
  }
}

export function normalizeQueryCodePayload(raw: JsonObject = {}) {
  const param = parseParamField(raw)
  return {
    appKey: normalizeIndustryString(raw.appkey),
    version: normalizeIndustryString(raw.version),
    timestamp: normalizeIndustryTimestamp(raw.timestamp),
    signMethod: normalizeIndustryString(raw.signMethod || 'MD5'),
    sign: normalizeIndustryString(raw.sign),
    accessToken: normalizeIndustryString(raw.access_token),
    method: normalizeIndustryString(raw.method),
    paramRaw: normalizeIndustryString(raw.param),

    oid: normalizeIndustryString(param.oid),
    sellerId: normalizeIndustryString(param.sellerId),
    eticketId: normalizeIndustryString(param.eticketId),
    sendType: normalizeIndustryString(param.sendType) || 'VIRTUAL',
    eticketType: normalizeIndustryString(param.eticketType),
    ext: normalizeIndustryString(param.ext),
  }
}

export function assertSendCodePayload(
  payload: ReturnType<typeof normalizeSendCodePayload>,
  config = assertKuaishouIndustryConfig(),
) {
  if (!payload.oid) {
    throw createHttpError('缺少 oid', {
      statusCode: 400,
      errorCode: 'kuaishou_industry_missing_oid',
    })
  }

  if (!payload.sendType) {
    throw createHttpError('缺少 sendType', {
      statusCode: 400,
      errorCode: 'kuaishou_industry_missing_send_type',
    })
  }

  if (!payload.sellerId) {
    throw createHttpError('缺少 sellerId', {
      statusCode: 400,
      errorCode: 'kuaishou_industry_missing_seller_id',
    })
  }

  assertCommonPayload(payload, config)
}

export function assertDestroyCodePayload(
  payload: ReturnType<typeof normalizeDestroyCodePayload>,
  config = assertKuaishouIndustryConfig(),
) {
  if (!payload.oid) {
    throw createHttpError('缺少 oid', {
      statusCode: 400,
      errorCode: 'kuaishou_industry_missing_oid',
    })
  }

  if (!payload.reason) {
    throw createHttpError('缺少 reason', {
      statusCode: 400,
      errorCode: 'kuaishou_industry_missing_reason',
    })
  }

  assertCommonPayload(payload, config)
}

export function assertQueryCodePayload(
  payload: ReturnType<typeof normalizeQueryCodePayload>,
  config = assertKuaishouIndustryConfig(),
) {
  if (!payload.oid) {
    throw createHttpError('缺少 oid', {
      statusCode: 400,
      errorCode: 'kuaishou_industry_missing_oid',
    })
  }

  assertCommonPayload(payload, config)
}

export function normalizeConsumeCodePayload(raw: JsonObject = {}) {
  const param = parseParamField(raw)
  return {
    appKey: normalizeIndustryString(raw.appkey),
    version: normalizeIndustryString(raw.version),
    timestamp: normalizeIndustryTimestamp(raw.timestamp),
    signMethod: normalizeIndustryString(raw.signMethod || 'MD5'),
    sign: normalizeIndustryString(raw.sign),
    accessToken: normalizeIndustryString(raw.access_token),
    method: normalizeIndustryString(raw.method),
    paramRaw: normalizeIndustryString(raw.param),

    oid: normalizeIndustryString(param.oid),
    sellerId: normalizeIndustryString(param.sellerId),
    etickets: normalizeConsumeEtickets(param.etickets),
    status: normalizeIndustryString(param.status),
    consumeType: normalizeIndustryString(param.consumeType),
    consumeTime: normalizeIndustryLong(param.consumeTime),
    storeName: normalizeIndustryString(param.storeName),
    storeAddress: normalizeIndustryString(param.storeAddress),
    expressNo: normalizeIndustryString(param.expressNo),
    expressCode: normalizeIndustryString(param.expressCode),
    appointmentTime: normalizeIndustryString(param.appointmentTime),
    eticketType: normalizeIndustryString(param.eticketType),
    ext: normalizeIndustryString(param.ext),
    token: normalizeIndustryString(param.token),
    seriallNum: normalizeIndustryString(param.seriallNum),
    consumePoiId: normalizeIndustryLong(param.consumePoiId),
  }
}

export function assertConsumeCodePayload(
  payload: ReturnType<typeof normalizeConsumeCodePayload>,
  config = assertKuaishouIndustryConfig(),
) {
  if (!payload.oid) {
    throw createHttpError('缺少 oid', {
      statusCode: 400,
      errorCode: 'kuaishou_industry_missing_oid',
    })
  }

  if (!Array.isArray(payload.etickets) || payload.etickets.length === 0) {
    throw createHttpError('缺少 etickets', {
      statusCode: 400,
      errorCode: 'kuaishou_industry_missing_etickets',
    })
  }

  if (!payload.status) {
    throw createHttpError('缺少 status', {
      statusCode: 400,
      errorCode: 'kuaishou_industry_missing_status',
    })
  }

  if (!payload.consumeType) {
    throw createHttpError('缺少 consumeType', {
      statusCode: 400,
      errorCode: 'kuaishou_industry_missing_consume_type',
    })
  }

  if (!payload.seriallNum) {
    throw createHttpError('缺少 seriallNum', {
      statusCode: 400,
      errorCode: 'kuaishou_industry_missing_serial_num',
    })
  }

  assertCommonPayload(payload, config)
}

function assertCommonPayload(
  payload: {
    appKey: string
    version: string
    timestamp: number
    signMethod: string
    sign: string
    method: string
    accessToken: string
    paramRaw: string
  },
  _config = assertKuaishouIndustryConfig(),
) {
  if (!payload.signMethod) {
    throw createHttpError('缺少 signMethod', {
      statusCode: 400,
      errorCode: 'kuaishou_industry_missing_sign_method',
    })
  }

  if (!payload.sign) {
    throw createHttpError('缺少 sign', {
      statusCode: 400,
      errorCode: 'kuaishou_industry_missing_sign',
    })
  }

  const normalizedMethod = payload.signMethod.toUpperCase()
  if (
    normalizedMethod !== 'MD5' &&
    normalizedMethod !== 'HMAC_SHA256' &&
    normalizedMethod !== 'HMAC-SHA256'
  ) {
    throw createHttpError(`不支持的签名算法: ${payload.signMethod}，仅支持 MD5 或 HMAC_SHA256`, {
      statusCode: 400,
      errorCode: 'kuaishou_industry_unsupported_sign_method',
    })
  }
}

function parseParamField(raw: JsonObject) {
  if (raw.param && typeof raw.param === 'object' && !Array.isArray(raw.param)) {
    return raw.param
  }

  try {
    const parsed = JSON.parse(normalizeIndustryString(raw.param || '{}'))
    return asJsonObject(parsed)
  } catch {
    return {}
  }
}

function normalizeIndustryInteger(value: unknown) {
  const parsed = Number(value)
  return Number.isInteger(parsed) ? parsed : 0
}

function normalizeIndustryLong(value: unknown) {
  const parsed = Number(value)
  return Number.isFinite(parsed) ? parsed : 0
}

function normalizeIndustryTimestamp(value: unknown) {
  const parsed = Number(value)
  return Number.isFinite(parsed) ? parsed : 0
}

function normalizeDestroyEtickets(value: unknown) {
  if (!Array.isArray(value)) {
    return []
  }

  return value.map((item) => ({
    id: normalizeIndustryString(item?.id),
    code: normalizeIndustryString(item?.code),
    num: normalizeIndustryInteger(item?.num),
    goodsValue: normalizeIndustryLong(item?.goodsValue),
  }))
}

function normalizeConsumeEtickets(value: unknown) {
  if (!Array.isArray(value)) {
    return []
  }

  return value.map((item) => ({
    id: normalizeIndustryString(item?.id),
    code: normalizeIndustryString(item?.code),
    num: normalizeIndustryInteger(item?.num),
    goodsValue: normalizeIndustryLong(item?.goodsValue),
  }))
}
