import { listTasksByOrderId } from '../../repositories/task-repo.js'
import { formatFenToAmount, parseAmountToFen } from '../../utils/money.js'
import { extractAgisoTradePayload, resolveAgisoTradePlatformOrderId } from '../order/agiso-trade-parsing.js'
import { safeParseJson } from './admin-query-utils.js'
import { resolveDisplayShopName } from './admin-read-shared-helpers.js'

import type { AdminWebhookEventListItem } from '../../types/admin-read-models.js'
import type { WebhookEventRow } from '../../types/repository-rows.js'

type JsonRecord = Record<string, any>

type MapAdminWebhookEventOptions = {
  includeRaw?: boolean
}

export async function mapAdminWebhookEvent(
  item: WebhookEventRow,
  { includeRaw = false }: MapAdminWebhookEventOptions = {},
): Promise<AdminWebhookEventListItem> {
  const headers = normalizeRecord(safeParseJson(item.headers_json))
  const query = normalizeRecord(safeParseJson(item.query_json))
  const body = normalizeRecord(safeParseJson(item.body_json))
  const payload = extractWebhookPayload(body)
  const itemSources = extractWebhookItemSources(payload)
  const rawAmount = pickFirstNonEmpty([
    payload.total_fee,
    payload.totalFee,
    payload.TotalFee,
    payload.pay_fee,
    payload.payFee,
    payload.Payment,
    payload.payment,
    payload.buy_amount,
    payload.buyAmount,
  ])
  const totalAmountFen = parseAmountToFen(rawAmount)
  const taskCount = item.related_order_id ? (await listTasksByOrderId(item.related_order_id)).length : 0
  const shopId = item.shop_id || pickFirstNonEmpty([
    payload.PlatformUserId,
    payload.platformUserId,
    payload.platform_user_id,
    payload.seller_id,
    payload.sellerId,
    payload.SellerId,
    payload.seller_nick,
    payload.sellerNick,
    payload.SellerNick,
  ])

  const mapped = {
    eventId: item.id,
    provider: item.provider || 'agiso',
    platform: item.platform,
    platformRaw: pickFirstNonEmpty([
      query.fromPlatform,
      query.from_platform,
      body.fromPlatform,
      body.from_platform,
      payload.fromPlatform,
      payload.FromPlatform,
      payload.platform,
      payload.Platform,
    ]),
    shopId,
    shopName: resolveDisplayShopName(
      item.provider,
      shopId,
      item.shop_name || pickFirstNonEmpty([
        payload.shopName,
        payload.shop_name,
        payload.ShopName,
        payload.seller_nick,
        payload.sellerNick,
        payload.SellerNick,
      ]),
    ),
    eventType: item.event_type,
    eventKey: item.event_key,
    signatureValid: Boolean(item.signature_valid),
    processed: Boolean(item.processed),
    processError: item.process_error,
    visibilityLevel: resolveWebhookVisibilityLevel(item.process_error),
    relatedOrderId: item.related_order_id,
    createdAt: item.created_at,
    platformOrderId: resolveAgisoTradePlatformOrderId(payload),
    buyerId: pickFirstNonEmpty([
      payload.buyer_id,
      payload.buyerId,
      payload.BuyerId,
      payload.openid,
      payload.BuyerOpenUid,
      payload.buyer_open_uid,
      payload.buyerOpenUid,
    ]),
    buyerName: pickFirstNonEmpty([
      payload.buyer_name,
      payload.buyerName,
      payload.BuyerName,
      payload.nick,
      payload.BuyerNick,
      payload.buyer_nick,
      payload.buyerNick,
    ]),
    totalAmount: rawAmount ? formatFenToAmount(totalAmountFen) : '',
    totalAmountFen,
    currency: pickFirstNonEmpty([payload.currency, payload.Currency, 'CNY']) || 'CNY',
    itemCount: itemSources.length,
    taskCount,
    messageText: pickFirstNonEmpty([
      payload.MsgTypeDes,
      payload.msgTypeDes,
      payload.msg_type_desc,
      payload.message,
      payload.msg,
    ]),
    requestTimestamp: pickFirstNonEmpty([query.timestamp]),
    requestSign: pickFirstNonEmpty([query.sign]),
    aopic: pickFirstNonEmpty([query.aopic]),
    sourceHost: pickFirstNonEmpty([headers['x-forwarded-host'], headers.host]),
    sourceIp: pickFirstNonEmpty([headers['x-forwarded-for'], headers['x-real-ip']]),
    userAgent: pickFirstNonEmpty([headers['user-agent'], headers['User-Agent']]),
  }

  if (!includeRaw) {
    return mapped
  }

  return {
    ...mapped,
    headers,
    query,
    body,
    payload,
  }
}

function extractWebhookPayload(body: JsonRecord): JsonRecord {
  return extractAgisoTradePayload(body)
}

function extractWebhookItemSources(payload: unknown): JsonRecord[] {
  const normalizedPayload = normalizeRecord(payload)
  const candidates = [
    normalizedPayload.orders,
    normalizedPayload.Orders,
    normalizedPayload.items,
    normalizedPayload.Items,
    normalizedPayload.order_items,
  ]

  for (const candidate of candidates) {
    if (Array.isArray(candidate) && candidate.length > 0) {
      return candidate.map((item) => normalizeRecord(item)).filter((item) => Object.keys(item).length > 0)
    }
  }

  if (
    pickFirstNonEmpty([
      normalizedPayload.item_id,
      normalizedPayload.itemId,
      normalizedPayload.ItemId,
      normalizedPayload.num_iid,
      normalizedPayload.numIid,
      normalizedPayload.NumIid,
    ])
  ) {
    return [normalizedPayload]
  }

  return []
}

export function resolveWebhookVisibilityLevel(processError: unknown): string {
  const normalized = String(processError || '').trim()

  if (normalized.startsWith('ignored_')) {
    return 'ignored'
  }

  return 'important'
}

function normalizeRecord(value: unknown): JsonRecord {
  return value && typeof value === 'object' && !Array.isArray(value) ? value : {}
}

function pickFirstNonEmpty(values: unknown[]): string {
  for (const value of values) {
    if (typeof value === 'string' && value.trim()) {
      return value.trim()
    }

    if (typeof value === 'number' && Number.isFinite(value)) {
      return String(value)
    }
  }

  return ''
}
