import type { JsonObject } from '../../../types/json.js'

import { affiliateDashRequest } from './http-client.js'

export type AffiliateDashOrder = ReturnType<typeof mapAffiliateDashOrder> & {
  /** 命中幂等（200 + idempotent=true）时为 true，仅创建订单响应存在 */
  idempotent?: boolean
}
export type AffiliateDashDeliveryInfo = ReturnType<typeof mapAffiliateDashDeliveryInfo>
export type AffiliateDashBindResult = ReturnType<typeof mapAffiliateDashBindResult>
export type AffiliateDashWallet = ReturnType<typeof mapAffiliateDashWallet>

const ORDERS_PATH = '/api/client/v1/orders'

export async function createAffiliateDashOrder(input: {
  clientOrderNo: string
  sku: string
  quantity?: number | undefined
  buyerReference?: string | undefined
  data?: JsonObject | undefined
}) {
  const payload: JsonObject = {
    client_order_no: input.clientOrderNo,
    sku: input.sku,
  }
  if (input.quantity !== undefined) {
    payload.quantity = input.quantity
  }
  if (input.buyerReference) {
    payload.buyer_reference = input.buyerReference
  }
  if (input.data !== undefined) {
    payload.data = input.data
  }

  const json = await affiliateDashRequest({
    method: 'POST',
    pathname: ORDERS_PATH,
    payload,
  })
  const data = asJsonObject(json.data)
  const order = mapAffiliateDashOrder(data.order)
  return {
    ...order,
    idempotent: Boolean(data.idempotent),
  }
}

export async function getAffiliateDashOrder(orderNo: string) {
  const json = await affiliateDashRequest({
    method: 'GET',
    pathname: `${ORDERS_PATH}/${encodeURIComponent(orderNo)}`,
  })
  return mapAffiliateDashOrder(json.data)
}

export async function getAffiliateDashDeliveryLink(orderNo: string) {
  const json = await affiliateDashRequest({
    method: 'GET',
    pathname: `${ORDERS_PATH}/${encodeURIComponent(orderNo)}/delivery-link`,
  })
  return mapAffiliateDashDeliveryLink(json.data)
}

export async function getAffiliateDashDelivery(orderNo: string) {
  const json = await affiliateDashRequest({
    method: 'GET',
    pathname: `${ORDERS_PATH}/${encodeURIComponent(orderNo)}/delivery`,
  })
  return mapAffiliateDashDeliveryInfo(json.data)
}

export async function bindAffiliateDashDelivery(input: { orderNo: string; gameAccount: string }) {
  const json = await affiliateDashRequest({
    method: 'POST',
    pathname: `${ORDERS_PATH}/${encodeURIComponent(input.orderNo)}/delivery/bind`,
    payload: { game_account: input.gameAccount },
  })
  return mapAffiliateDashBindResult(json.data)
}

export async function getAffiliateDashBindResult(input: { orderNo: string; bindUuid: string }) {
  const json = await affiliateDashRequest({
    method: 'GET',
    pathname:
      `${ORDERS_PATH}/${encodeURIComponent(input.orderNo)}/delivery/bind-result` +
      `?bind_uuid=${encodeURIComponent(input.bindUuid)}`,
  })
  return mapAffiliateDashBindResult(json.data)
}

export async function submitAffiliateDashDelivery(input: {
  orderNo: string
  gameAccount: string
  bindUuid: string
}) {
  const json = await affiliateDashRequest({
    method: 'POST',
    pathname: `${ORDERS_PATH}/${encodeURIComponent(input.orderNo)}/delivery/submit`,
    payload: {
      game_account: input.gameAccount,
      bind_uuid: input.bindUuid,
    },
  })
  return mapAffiliateDashSubmitResult(json.data)
}

export async function getAffiliateDashWallet() {
  const json = await affiliateDashRequest({
    method: 'GET',
    pathname: '/api/client/v1/wallet',
  })
  return mapAffiliateDashWallet(json.data)
}

export function mapAffiliateDashOrder(value: unknown) {
  const source = asJsonObject(value)
  const product = asJsonObject(source.product)

  return {
    orderNo: asString(source.order_no),
    clientOrderNo: asString(source.client_order_no),
    sku: asString(source.sku || source.product_sku || product.sku),
    productName: asString(product.display_name || product.name),
    quantity: asInteger(source.quantity, 1),
    baseAmount: asNumber(source.base_amount),
    serviceFeeAmount: asNumber(source.service_fee_amount),
    amount: asNumber(source.amount),
    currency: asString(source.currency),
    feeType: asString(source.fee_type),
    buyerReference: asString(source.buyer_reference),
    orderStatus: asString(source.order_status),
    canShip: asBoolean(source.can_ship),
    cannotShipReason: asString(source.cannot_ship_reason),
    providerOrderNo: asString(source.provider_order_no),
    failureReason: asString(source.failure_reason),
    data: isJsonObject(source.data) ? source.data : {},
    result: asString(source.result),
    createdAt: asString(source.created_at),
    deliveredAt: asString(source.delivered_at),
    cancelledAt: asString(source.cancelled_at),
    raw: isJsonObject(source) ? source : {},
  }
}

function mapAffiliateDashDeliveryLink(value: unknown) {
  const source = asJsonObject(value)
  return {
    orderNo: asString(source.order_no),
    deliveryUrl: asString(source.delivery_url),
    expiresAt: asString(source.expires_at),
    expiresInSeconds: asInteger(source.exp, undefined),
  }
}

function mapAffiliateDashDeliveryInfo(value: unknown) {
  const source = asJsonObject(value)
  const product = asJsonObject(source.product)
  const good = asJsonObject(source.good)

  return {
    status: asString(source.status),
    canShip: asBoolean(source.can_ship),
    cannotShipReason: asString(source.cannot_ship_reason),
    product: {
      sku: asString(product.sku),
      displayName: asString(product.display_name || product.name),
      priceAmount: asNumber(product.price_amount),
      currency: asString(product.currency),
    },
    buyerName: asString(source.buyer_name),
    gameChannel: asString(source.game_channel),
    gameUid: asString(source.game_uid),
    roleName: asString(source.role_name),
    payScore: asNumber(source.pay_score),
    data: isJsonObject(source.data) ? source.data : {},
    good: isJsonObject(good) ? good : {},
  }
}

function mapAffiliateDashBindResult(value: unknown) {
  const source = asJsonObject(value)
  return {
    bindUuid: asString(source.bind_uuid),
    bindUrl: asString(source.bind_url),
    qrUrl: asString(source.qr_url),
    bound: asBoolean(source.bound),
    gameAccount: asString(source.game_account),
    roleName: asString(source.role_name),
    gameChannel: asString(source.game_channel),
    expectedGameAccount: asString(source.expected_game_account),
    mismatch: asBoolean(source.mismatch),
  }
}

function mapAffiliateDashSubmitResult(value: unknown) {
  const source = asJsonObject(value)
  return {
    orderNo: asString(source.order_no),
    status: asString(source.status),
    message: asString(source.message),
    providerOrderNo: asString(source.provider_order_no),
  }
}

function mapAffiliateDashWallet(value: unknown) {
  const source = asJsonObject(value)
  return {
    availableBalance: asNumber(source.available_balance),
    frozenBalance: asNumber(source.frozen_balance),
    currency: asString(source.currency),
  }
}

function asJsonObject(value: unknown) {
  return isJsonObject(value) ? value : {}
}

function isJsonObject(value: unknown): value is JsonObject {
  return Object.prototype.toString.call(value) === '[object Object]'
}

function asString(value: unknown) {
  return String(value ?? '').trim()
}

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

function asInteger(value: unknown, fallback: number | undefined) {
  const parsed = Number(value)
  if (!Number.isInteger(parsed)) {
    return fallback
  }
  return parsed
}

function asBoolean(value: unknown) {
  return Boolean(value)
}
