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

import { createTaskEvent } from '../../../repositories/task-event-repo.js'
import { findKuaishouFeifeiTaskByOrder } from '../../../repositories/task-repo.js'
import { syncKuaishouFeifeiTaskStatus } from '../../fulfillment/kuaishou-feifei/index.js'
import { createHttpError } from '../../../utils/http.js'
import { nowIso } from '../../../utils/time.js'
import { assertKuaishouFeifeiConfig } from './config.js'
import { signKuaishouFeifeiPayload } from './http-client.js'
import { mapKuaishouFeifeiOrder } from './order-service.js'

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

export async function handleKuaishouFeifeiNotify(input: {
  body: unknown
  headers: NotifyHeaders
  rawBody?: string | undefined
}) {
  const config = assertKuaishouFeifeiConfig()
  const rawBody = String(input.rawBody || '')
  const appKey = normalizeHeader(input.headers['x-app-key'])
  const timestamp = normalizeHeader(input.headers['x-timestamp'])
  const sign = normalizeHeader(input.headers['x-sign'])

  if (!rawBody) {
    throw createHttpError('kuaishou-feifei 通知原始请求体缺失', {
      statusCode: 400,
      errorCode: 'kuaishou_feifei_notify_raw_body_missing',
    })
  }

  if (!appKey || appKey !== config.appKey) {
    throw createHttpError('kuaishou-feifei 通知 App Key 无效', {
      statusCode: 401,
      errorCode: 'kuaishou_feifei_notify_app_key_invalid',
    })
  }

  if (!timestamp || !sign) {
    throw createHttpError('kuaishou-feifei 通知签名参数缺失', {
      statusCode: 401,
      errorCode: 'kuaishou_feifei_notify_sign_missing',
    })
  }

  if (
    !verifyKuaishouFeifeiNotifySignature({
      appKey,
      appSecret: config.appSecret,
      timestamp,
      rawBody,
      sign,
    })
  ) {
    throw createHttpError('kuaishou-feifei 通知验签失败', {
      statusCode: 401,
      errorCode: 'kuaishou_feifei_notify_sign_invalid',
    })
  }

  const source = isPlainObject(input.body) ? input.body : {}
  const event = String(source.event || '').trim()
  const order = mapKuaishouFeifeiOrder(source.order)

  if (!order.platformOrderNo && !order.orderNo) {
    throw createHttpError('kuaishou-feifei 通知订单号缺失', {
      statusCode: 400,
      errorCode: 'kuaishou_feifei_notify_order_no_missing',
    })
  }

  const task = await findKuaishouFeifeiTaskByOrder({
    platformOrderNo: order.platformOrderNo,
    orderNo: order.orderNo,
  })

  if (!task) {
    throw createHttpError('kuaishou-feifei 通知未匹配到本地任务', {
      statusCode: 404,
      errorCode: 'kuaishou_feifei_notify_task_not_found',
      context: {
        platformOrderNo: order.platformOrderNo,
        orderNo: order.orderNo,
      },
    })
  }

  const now = nowIso()
  await createTaskEvent(
    task.id,
    'kuaishou_feifei_notify_received',
    {
      event,
      platformOrderNo: order.platformOrderNo,
      orderNo: order.orderNo,
      productCode: order.productCode,
      rechargeStatus: order.rechargeStatus,
      rechargeStatusLabel: order.rechargeStatusLabel,
      raw: order.raw,
    },
    now,
  )

  const updatedTask = await syncKuaishouFeifeiTaskStatus(task)

  return {
    ok: true,
    event,
    taskId: task.id,
    platformOrderNo: order.platformOrderNo,
    orderNo: order.orderNo,
    rechargeStatus: order.rechargeStatus,
    rechargeStatusLabel: order.rechargeStatusLabel,
    taskStatus: updatedTask.task_status,
    deliveryStatus: updatedTask.delivery_status,
  }
}

export function verifyKuaishouFeifeiNotifySignature(input: {
  appKey: string
  appSecret: string
  timestamp: string
  rawBody: string
  sign: string
}) {
  const expected = signKuaishouFeifeiPayload({
    appKey: input.appKey,
    appSecret: input.appSecret,
    timestamp: input.timestamp,
    body: input.rawBody,
  })

  return timingSafeEqualString(
    expected,
    String(input.sign || '')
      .trim()
      .toLowerCase(),
  )
}

function normalizeHeader(value: string | string[] | undefined) {
  return Array.isArray(value) ? String(value[0] || '').trim() : String(value || '').trim()
}

function timingSafeEqualString(left: string, right: string) {
  const leftBuffer = Buffer.from(left, 'utf8')
  const rightBuffer = Buffer.from(right, 'utf8')

  if (leftBuffer.length !== rightBuffer.length) {
    return false
  }

  return crypto.timingSafeEqual(leftBuffer, rightBuffer)
}

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