import { query } from '../../../db/client.js'
import {
  createOrder,
  findLatestOrderByPlatformOrderId,
  getOrderById,
  updateOrder,
} from '../../../repositories/order-repo.js'
import {
  listOrderItemsByOrderId,
  replaceOrderItems,
} from '../../../repositories/order-item-repo.js'
import { listTasksByOrderId } from '../../../repositories/task-repo.js'
import { upsertOrderFromSource } from '../../order/order-service.js'
import { syncWorkerOrdersForSourceOrder } from '../../worker-platform/index.js'
import { bindKuaishouIndustryVouchersToOrderTasks } from '../kuaishou-industry/voucher-binding-service.js'
import { asJsonObject, type JsonObject } from '../../../types/json.js'
import { OPEN_91_PLATFORM, OPEN_91_PROVIDER } from '../../open-91/config.js'
import { normalizeOpen91CreatePayload } from '../../open-91/payload.js'
import { buildOpen91OutTradeNo } from '../../open-91/response.js'
import { createHttpError } from '../../../utils/http.js'
import { parseAmountToFen } from '../../../utils/money.js'
import { nowIso } from '../../../utils/time.js'
import type { OrderItemRow, OrderRow } from '../../../types/repository/rows.js'

export const OPEN_91_PENDING_CONFIG_STATUS = 'pending_config'
export const OPEN_91_MANUAL_FAILED_STATUS = 'manual_failed'

export function buildOpen91SourceEvent(payload: JsonObject = {}, config: JsonObject = {}) {
  const normalized = normalizeOpen91CreatePayload(payload)
  const productInfo = parseOpen91ProductNo(normalized.productNo)
  const productNo = productInfo.rawProductNo
  const productName = productInfo.productName
  const shopId = String(config.shopId || OPEN_91_PROVIDER).trim() || OPEN_91_PROVIDER
  const shopName = String(config.shopName || '91卡券').trim() || '91卡券'
  const maxAmountFen = parseAmountToFen(normalized.maxAmount)

  return {
    provider: OPEN_91_PROVIDER,
    platform: OPEN_91_PLATFORM,
    shopId,
    shopName,
    platformOrderId: normalized.orderNo,
    orderStatus: 'paid',
    payStatus: 'paid',
    buyerId: '',
    buyerName: '',
    receiverContact: '',
    totalAmount: maxAmountFen,
    currency: 'CNY',
    paidAt: nowIso(),
    rawPayload: {
      source: OPEN_91_PROVIDER,
      receivedAt: nowIso(),
      body: normalized,
    },
    items: [
      {
        itemId: productNo,
        externalItemId: productNo,
        externalSkuCode: productNo,
        externalSkuName: productName,
        skuCode: productName,
        skuName: productName,
        quantity: normalized.buyNum,
        spec: {
          source: OPEN_91_PROVIDER,
          orderNo: normalized.orderNo,
          productNo,
          productName,
          shopId: productInfo.shopId,
          maxAmount: normalized.maxAmount,
        },
        snapshot: {
          source: OPEN_91_PROVIDER,
          orderNo: normalized.orderNo,
          productNo,
          productName,
          shopId: productInfo.shopId,
          maxAmount: normalized.maxAmount,
          maxAmountFen,
          externalItemId: productNo,
          externalSkuCode: productNo,
          externalSkuName: productName,
          callbackUrl: normalized.callbackUrl,
        },
      },
    ],
  }
}

export function parseOpen91ProductNo(value: unknown) {
  const rawProductNo = String(value || '').trim()
  const delimiter = '----'
  const delimiterIndex = rawProductNo.lastIndexOf(delimiter)

  if (delimiterIndex <= 0) {
    return {
      rawProductNo,
      productName: rawProductNo,
      shopId: '',
    }
  }

  const productName = rawProductNo.slice(0, delimiterIndex).trim()
  const shopId = rawProductNo.slice(delimiterIndex + delimiter.length).trim()

  if (!productName || !shopId) {
    return {
      rawProductNo,
      productName: rawProductNo,
      shopId: '',
    }
  }

  return {
    rawProductNo,
    productName,
    shopId,
  }
}

export async function upsertOpen91PendingOrder(payload: JsonObject = {}, config: JsonObject = {}) {
  const event = buildOpen91SourceEvent(payload, config)
  const now = nowIso()
  const existing = await findLatestOrderByPlatformOrderId({
    provider: event.provider,
    platform: event.platform,
    platformOrderId: event.platformOrderId,
  })

  const rawPayloadJson = JSON.stringify({
    ...event.rawPayload,
    pendingReason: 'unconfigured_items',
    pendingAt: now,
  })
  const orderPayload = {
    provider: event.provider,
    platform: event.platform,
    shopId: String(existing?.shop_id || event.shopId || '').trim(),
    shopName: String(existing?.shop_name || event.shopName || '').trim(),
    platformOrderId: event.platformOrderId,
    orderStatus: OPEN_91_PENDING_CONFIG_STATUS,
    payStatus: 'paid',
    buyerId: '',
    buyerName: '',
    receiverContact: '',
    totalAmount: event.totalAmount,
    currency: 'CNY',
    rawPayloadJson,
    paidAt: existing?.paid_at || now,
  }

  const order = existing
    ? await updateOrder(existing.id, { ...orderPayload, updatedAt: now })
    : await createOrder({ ...orderPayload, createdAt: now, updatedAt: now })

  if (!order) {
    throw createHttpError('91卡券待处理订单保存失败', {
      statusCode: 500,
      errorCode: 'open91_pending_order_save_failed',
    })
  }

  const [item] = event.items
  if (!item) {
    throw createHttpError('91卡券订单商品明细为空', {
      statusCode: 400,
      errorCode: 'open91_order_item_required',
    })
  }

  const orderItems = await replaceOrderItems(order.id, [
    {
      skuCode: item.skuCode,
      skuName: item.skuName,
      quantity: item.quantity,
      specJson: JSON.stringify(item.spec || {}),
      itemSnapshotJson: JSON.stringify(item.snapshot || item.spec || {}),
      createdAt: now,
      updatedAt: now,
    },
  ])
  await bindKuaishouIndustryVouchersToOrderTasks(order, [], {
    source: 'open91_pending_order',
    now,
  })
  await syncWorkerOrdersForSourceOrder(order, orderItems, {
    source: 'open91_pending_order',
    autoOnly: true,
  })

  return {
    order,
    orderItems,
    tasks: [] as JsonObject[],
  }
}

export async function retryOpen91Order(orderId: string | number) {
  const order = await getRequiredOpen91Order(orderId)
  const items = await listOrderItemsByOrderId(order.id)
  const event = buildOpen91SourceEventFromOrder(order, items)
  const result = await upsertOrderFromSource(event, { sourceLabel: 'open91-admin-retry' })

  if (result.ignored) {
    throw createHttpError('当前 91 订单仍未命中履约配置，请先补全商品规则', {
      statusCode: 409,
      errorCode: 'open91_order_still_unconfigured',
      context: {
        ignoreReason: result.ignoreReason || 'unconfigured_items',
      },
    })
  }

  return {
    order: result.order,
    orderItems: result.orderItems || [],
    tasks: result.tasks || [],
  }
}

export async function failOpen91Order(orderId: string | number, reason = '') {
  const order = await getRequiredOpen91Order(orderId)
  const now = nowIso()
  const rawPayload = parseJsonObject(order.raw_payload_json)
  const updated = await updateOrder(order.id, {
    provider: order.provider,
    platform: order.platform,
    shopId: order.shop_id,
    shopName: order.shop_name,
    platformOrderId: order.platform_order_id,
    orderStatus: OPEN_91_MANUAL_FAILED_STATUS,
    payStatus: order.pay_status,
    buyerId: order.buyer_id,
    buyerName: order.buyer_name,
    receiverContact: order.receiver_contact,
    totalAmount: order.total_amount,
    currency: order.currency,
    rawPayloadJson: JSON.stringify({
      ...rawPayload,
      manualFailedAt: now,
      manualFailedReason: String(reason || '').trim() || '商家手动标记无法履约',
    }),
    paidAt: order.paid_at,
    updatedAt: now,
  })

  return {
    order: updated,
    orderItems: await listOrderItemsByOrderId(order.id),
    tasks: await listTasksByOrderId(order.id),
  }
}

export async function listOpen91Orders({
  page = 1,
  pageSize = 20,
  status = 'pending_config',
} = {}) {
  const normalizedPage = Math.max(1, Number(page) || 1)
  const normalizedPageSize = Math.min(100, Math.max(1, Number(pageSize) || 20))
  const normalizedStatus = String(status || 'pending_config').trim()
  const filters = ['o.provider = $1', 'o.platform = $2']
  const params: Array<string | number> = [OPEN_91_PROVIDER, OPEN_91_PLATFORM]

  if (normalizedStatus && normalizedStatus !== 'all') {
    params.push(normalizedStatus)
    filters.push(`o.order_status = $${params.length}`)
  }

  const whereClause = `WHERE ${filters.join(' AND ')}`
  const totalResult = await query(
    `SELECT COUNT(*)::int AS total FROM orders o ${whereClause}`,
    params,
  )

  params.push(normalizedPageSize)
  params.push((normalizedPage - 1) * normalizedPageSize)
  const rowsResult = await query(
    `
      SELECT
        o.*,
        COALESCE(item_summary.items, '[]'::jsonb) AS items_json,
        COALESCE(task_summary.task_count, 0)::int AS task_count
      FROM orders o
      LEFT JOIN LATERAL (
        SELECT jsonb_agg(jsonb_build_object(
          'orderItemId', oi.id,
          'skuCode', oi.sku_code,
          'skuName', oi.sku_name,
          'quantity', oi.quantity,
          'snapshot', oi.item_snapshot_json
        ) ORDER BY oi.id ASC) AS items
        FROM order_items oi
        WHERE oi.order_id = o.id
      ) item_summary ON TRUE
      LEFT JOIN LATERAL (
        SELECT COUNT(*)::int AS task_count
        FROM fulfillment_tasks ft
        WHERE ft.order_id = o.id
      ) task_summary ON TRUE
      ${whereClause}
      ORDER BY o.id DESC
      LIMIT $${params.length - 1} OFFSET $${params.length}
    `,
    params,
  )

  return {
    page: normalizedPage,
    pageSize: normalizedPageSize,
    total: Number(totalResult.rows[0]?.total || 0),
    items: rowsResult.rows.map((row) => mapOpen91AdminOrderRow(row)),
  }
}

export async function getRequiredOpen91Order(orderId: string | number) {
  const order = await getOrderById(Number(orderId))

  if (!order || order.provider !== OPEN_91_PROVIDER || order.platform !== OPEN_91_PLATFORM) {
    throw createHttpError('91卡券订单不存在', {
      statusCode: 404,
      errorCode: 'open91_order_not_found',
    })
  }

  return order
}

function buildOpen91SourceEventFromOrder(order: OrderRow, items: OrderItemRow[] = []) {
  const rawPayload = parseJsonObject(order.raw_payload_json)
  const body = parseJsonObject(rawPayload.body)
  const normalizedItems = Array.isArray(items) ? items : []
  const eventItems = normalizedItems.map((item: OrderItemRow) => {
    const snapshot = parseJsonObject(item.item_snapshot_json)
    const productNo = String(
      snapshot.productNo || snapshot.externalSkuCode || item.sku_code || '',
    ).trim()

    return {
      itemId: productNo,
      externalItemId: String(snapshot.externalItemId || productNo).trim(),
      externalSkuCode: String(snapshot.externalSkuCode || productNo).trim(),
      externalSkuName: String(snapshot.externalSkuName || item.sku_name || productNo).trim(),
      skuCode: productNo,
      skuName: String(item.sku_name || productNo).trim(),
      quantity: Math.max(1, Number(item.quantity || body.buyNum || 1) || 1),
      spec: parseJsonObject(item.spec_json),
      snapshot,
    }
  })

  return {
    provider: order.provider,
    platform: order.platform,
    shopId: OPEN_91_PROVIDER,
    shopName: String(order.shop_id || '').trim() === OPEN_91_PROVIDER ? order.shop_name : '91卡券',
    platformOrderId: order.platform_order_id,
    orderStatus: 'paid',
    payStatus: 'paid',
    buyerId: order.buyer_id || '',
    buyerName: order.buyer_name || '',
    receiverContact: order.receiver_contact || '',
    totalAmount: Number(order.total_amount || 0) || 0,
    currency: order.currency || 'CNY',
    paidAt: order.paid_at || nowIso(),
    rawPayload: {
      ...rawPayload,
      retriedAt: nowIso(),
    },
    items: eventItems,
  }
}

function mapOpen91AdminOrderRow(row: JsonObject) {
  const rawPayload = parseJsonObject(row.raw_payload_json)
  const items = Array.isArray(row.items_json) ? row.items_json : []
  const firstItem = items[0] || {}
  const firstSnapshot = parseJsonObject(firstItem.snapshot)
  const failReason = String(rawPayload.manualFailedReason || '').trim()

  return {
    orderId: Number(row.id || 0),
    orderNo: String(row.platform_order_id || '').trim(),
    outTradeNo: buildOpen91OutTradeNo(row),
    orderStatus: String(row.order_status || '').trim(),
    payStatus: String(row.pay_status || '').trim(),
    shopId: String(row.shop_id || '').trim(),
    shopName: String(row.shop_name || '').trim(),
    productNo: String(
      firstSnapshot.productNo || firstSnapshot.externalSkuCode || firstItem.skuCode || '',
    ).trim(),
    productName: String(firstSnapshot.externalSkuName || firstItem.skuName || '').trim(),
    buyNum: Number(firstItem.quantity || 0),
    taskCount: Number(row.task_count || 0),
    failReason,
    createdAt: row.created_at,
    updatedAt: row.updated_at,
    items,
  }
}

function parseJsonObject(value: unknown): JsonObject {
  if (!value) {
    return {}
  }

  if (typeof value === 'object' && !Array.isArray(value)) {
    return value
  }

  try {
    const parsed = JSON.parse(String(value || '{}'))
    return asJsonObject(parsed)
  } catch {
    return {}
  }
}
