import { createHttpError } from '../../../utils/http.js'
import { logInfo } from '../../../utils/logger.js'
import { cloudtentaclesRequest } from './http-client.js'
import { resolveCloudtentaclesConfig } from './helpers.js'
import type { JsonObject } from '../../../types/json.js'

export type CloudtentaclesDeliveryRecordQuery = JsonObject & {
  baseUrl?: string
  timeoutMs?: number | string
  token?: string
  deviceId?: string
  deviceType?: number | string
  page?: number | string
  size?: number | string
  startDate?: string
  endDate?: string
  recordCode?: number | string
}

export async function listCloudtentaclesDeliveryRecords(
  payload: CloudtentaclesDeliveryRecordQuery = {},
) {
  const config = resolveCloudtentaclesConfig({
    ...pickDefined({
      baseUrl: payload.baseUrl,
      deviceId: payload.deviceId,
      deviceType: payload.deviceType,
    }),
    ...(typeof payload.timeoutMs === 'undefined'
      ? {}
      : { timeoutMs: normalizePositiveInteger(payload.timeoutMs, 5000) }),
  })
  const page = normalizePositiveInteger(payload.page, 1)
  const size = normalizePageSize(payload.size)
  const startDate = normalizeDateInput(payload.startDate)
  const endDate = normalizeDateInput(payload.endDate)

  if (!String(payload.token || '').trim()) {
    throw createHttpError('cloudtentacles 发货记录查询缺少 token', {
      statusCode: 409,
      errorCode: 'cloudtentacles_record_missing_token',
    })
  }

  if (!startDate || !endDate) {
    throw createHttpError('cloudtentacles 发货记录查询需要选择开始和结束时间', {
      statusCode: 400,
      errorCode: 'cloudtentacles_record_date_required',
    })
  }

  const result = await cloudtentaclesRequest('/record/paging', {
    ...payload,
    method: 'POST',
    body: {
      record_code: normalizePositiveInteger(payload.recordCode, 4),
      page,
      size,
      start_date: startDate,
      end_date: endDate,
    },
    businessErrorCode: 'cloudtentacles_record_query_failed',
    timeoutMs: payload.timeoutMs || config.timeoutMs,
  })

  const data = isPlainObject(result.payload?.data) ? result.payload.data : {}
  const values = Array.isArray(data.values) ? data.values : []
  const total = normalizeNonNegativeInteger(data.total, values.length)

  logInfo('[cloudtentacles/records]', '发货记录查询完成', {
    page,
    size,
    recordCode: normalizePositiveInteger(payload.recordCode, 4),
    startDate,
    endDate,
    total,
    returnedCount: values.length,
  })

  return {
    baseUrl: config.baseUrl,
    page,
    size,
    total,
    items: values.map(mapCloudtentaclesDeliveryRecord),
    raw: data,
  }
}

function mapCloudtentaclesDeliveryRecord(raw: JsonObject) {
  return {
    createdAt: String(raw.c_time || '').trim(),
    recordId: String(raw.record_id || '').trim(),
    virtualNumberId: normalizeNonNegativeInteger(raw.virtual_number_id, 0),
    userId: normalizeNonNegativeInteger(raw.user_id, 0),
    count: normalizeNonNegativeInteger(raw.count, 0),
    cdk: String(raw.cdk || '').trim(),
    exchangeUrl: String(raw.exchange_url || '').trim(),
    name: String(raw.name || '').trim(),
    phone: String(raw.phone || '').trim(),
    status: normalizeNonNegativeInteger(raw.status, 0),
    fulfillUser: String(raw.fulfill_user || '').trim(),
    operatorName: String(raw.u_name || '').trim(),
    raw,
  }
}

function normalizePositiveInteger(value: unknown, fallback: number) {
  const parsed = Number(value)
  return Number.isInteger(parsed) && parsed > 0 ? parsed : fallback
}

function normalizePageSize(value: unknown) {
  const parsed = normalizePositiveInteger(value, 100)
  return Math.min(Math.max(parsed, 100), 1000)
}

function normalizeNonNegativeInteger(value: unknown, fallback: number) {
  const parsed = Number(value)
  return Number.isInteger(parsed) && parsed >= 0 ? parsed : fallback
}

function normalizeDateInput(value: unknown) {
  const raw = String(value || '').trim()
  if (!raw) {
    return ''
  }

  const date = new Date(raw)
  return Number.isNaN(date.getTime()) ? raw : date.toISOString()
}

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

function pickDefined(values: JsonObject = {}) {
  return Object.fromEntries(
    Object.entries(values).filter(([, value]) => typeof value !== 'undefined'),
  )
}
