import { createTaskEvent } from '../../../repositories/task-event-repo.js'
import { findAffiliateDashTaskByOrder } from '../../../repositories/task-repo.js'
import { insertWebhookEventOnce } from '../../../repositories/webhook-event-repo.js'
import type { JsonObject } from '../../../types/json.js'
import { syncAffiliateDashTaskStatus } from '../../fulfillment/affiliate-dash/index.js'
import { createHttpError } from '../../../utils/http.js'
import { nowIso } from '../../../utils/time.js'
import { verifyAffiliateDashCallback } from './verify-callback.js'

type NotifyHeaders = Record<string, string | string[] | undefined>

/**
 * affiliate-dash 回调入口（验签 + 幂等去重 + 状态同步）。
 *
 * 处理顺序：
 * 1. 验签（X-Timestamp 容差 → 重算签名）并解析事件；
 * 2. 按 order_no / client_order_no 查本地任务（未匹配 → 404，触发对方重试）；
 * 3. 幂等闸门：webhook_events(provider + event_id 唯一)，重复回调直接 200 跳过；
 * 4. 记录任务事件 + 状态合并式同步（可重入）。
 */
export async function handleAffiliateDashNotify(input: {
  body: unknown
  headers: NotifyHeaders
  rawBody?: string | undefined
}) {
  const verified = verifyAffiliateDashCallback({
    headers: input.headers,
    rawBody: input.rawBody,
  })

  const data = isPlainObject(verified.data) ? verified.data : {}
  const orderNo = String(data.order_no || '').trim()
  const clientOrderNo = String(data.client_order_no || '').trim()
  const orderStatus = String(data.order_status || '').trim()

  if (!orderNo && !clientOrderNo) {
    throw createHttpError('affiliate-dash 回调订单号缺失', {
      statusCode: 400,
      errorCode: 'affiliate_dash_callback_order_no_missing',
    })
  }

  const task = await findAffiliateDashTaskByOrder({
    orderNo,
    clientOrderNo,
  })

  if (!task) {
    throw createHttpError('affiliate-dash 回调未匹配到本地任务', {
      statusCode: 404,
      errorCode: 'affiliate_dash_callback_task_not_found',
      context: {
        orderNo,
        clientOrderNo,
      },
    })
  }

  const rawBody = String(input.rawBody || '')
  let payload: JsonObject = {}
  try {
    const parsed = JSON.parse(rawBody)
    if (isPlainObject(parsed)) {
      payload = parsed
    }
  } catch {
    payload = { order_no: orderNo, client_order_no: clientOrderNo, order_status: orderStatus }
  }

  const dedupe = await insertWebhookEventOnce({
    provider: 'affiliate_dash',
    eventId: verified.eventId,
    eventType: verified.event,
    taskId: task.id,
    payload,
  })

  if (!dedupe.inserted) {
    return {
      ok: true,
      duplicate: true,
      eventId: verified.eventId,
      event: verified.event,
      taskId: task.id,
      orderNo,
      orderStatus,
    }
  }

  const now = nowIso()
  await createTaskEvent(
    task.id,
    'affiliate_dash_notify_received',
    {
      event: verified.event,
      eventId: verified.eventId,
      occurredAt: verified.occurredAt,
      orderNo,
      clientOrderNo,
      orderStatus,
      raw: data,
    },
    now,
  )

  const updatedTask = await syncAffiliateDashTaskStatus(task)

  return {
    ok: true,
    duplicate: false,
    eventId: verified.eventId,
    event: verified.event,
    taskId: task.id,
    orderNo,
    clientOrderNo,
    orderStatus,
    taskStatus: updatedTask.task_status,
    deliveryStatus: updatedTask.delivery_status,
  }
}

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