import {
  countWorkCategoryUsages,
  deleteWorkCategory,
  getWorkCategoryById,
  listAllWorkCategories,
  upsertWorkCategory,
} from '../../repositories/worker-platform/work-category-repo.js'
import {
  countWorkerLevelUsages,
  deleteWorkerLevel,
  getWorkerLevelById,
  getWorkerLevelByKey,
  listWorkerLevels,
  upsertWorkerLevel,
} from '../../repositories/worker-platform/worker-repo.js'
import {
  countWorkProductRulesByCategory,
  deleteWorkProductRule,
  getWorkProductRuleById,
  listOpenWorkOrdersByProductRuleId,
  listWorkProductRulesPage,
  syncOpenWorkOrderPriceFromRule,
  upsertWorkProductRule,
} from '../../repositories/worker-platform/work-product-rule-repo.js'
import type { WorkOrderRow, WorkProductRuleRow } from '../../repositories/worker-platform/types.js'
import {
  normalizeWorkOrderAcceptanceMode,
  normalizeWorkOrderGiftCooldownHours,
  normalizeWorkOrderGiftCooldownMinutes,
  WORK_ORDER_ACCEPTANCE_MODE,
} from '../../domain/work-order-acceptance-mode.js'
import type { JsonObject } from '../../types/json.js'
import { createHttpError } from '../../utils/http.js'
import { randomId } from '../../utils/random.js'
import { nowIso } from '../../utils/time.js'
import { normalizePage, normalizePageSize, safeParseJson } from '../admin/admin-query-utils.js'
import { publishWorkOrderRealtimeChange } from '../realtime/realtime-event-service.js'
import {
  DEFAULT_CATEGORY_KEY,
  DEFAULT_LEVEL_KEY,
  DEFAULT_LEVEL_NAME,
  mapWorkCategory,
  mapWorkProductRule,
  mapWorkerLevel,
  normalizeAmountFen,
  normalizeBoolean,
  normalizeEnabledStatus,
  normalizeInteger,
  normalizeMatchType,
  normalizeOptionalId,
  normalizePositiveInteger,
  normalizeRequirementFieldsFromPayload,
  normalizeSlugKey,
  normalizeWorkProductRuleMatch,
  resolveSkuNameQuantity,
  resolveWorkOrderRulePricing,
} from './mappers.js'
import { ensureWorkerPlatformDefaults } from './worker-platform-defaults.js'
import { normalizeWorkOrderTimeoutPolicy } from './work-order-timeout-policy.js'

export async function listAdminWorkerLevels() {
  await ensureWorkerPlatformDefaults()
  return { items: (await listWorkerLevels()).map(mapWorkerLevel) }
}

export async function listAdminWorkCategories() {
  await ensureWorkerPlatformDefaults()
  return { items: (await listAllWorkCategories()).map(mapWorkCategory) }
}

export async function saveAdminWorkCategory(payload: JsonObject = {}) {
  const now = nowIso()
  const categoryKey = normalizeSlugKey(
    payload.categoryKey || payload.category_key || payload.name,
    DEFAULT_CATEGORY_KEY,
  )
  const name = String(payload.name || '').trim() || '默认分类'
  const category = await upsertWorkCategory({
    categoryKey,
    name,
    sortOrder: normalizeInteger(payload.sortOrder, 100),
    status: normalizeEnabledStatus(payload.status),
    now,
  })
  return { category: mapWorkCategory(category) }
}

export async function deleteAdminWorkCategory(categoryId: number | string) {
  const category = await getWorkCategoryById(Number(categoryId))
  if (!category) {
    throw createHttpError('分类不存在', {
      statusCode: 404,
      errorCode: 'work_category_not_found',
    })
  }
  const usages = await countWorkCategoryUsages(Number(categoryId))
  if (usages.workOrderCount > 0 || usages.productRuleCount > 0) {
    throw createHttpError(
      `该分类已被 ${usages.workOrderCount} 个工单和 ${usages.productRuleCount} 条物品规则使用，无法删除，请先停用`,
      {
        statusCode: 409,
        errorCode: 'work_category_in_use',
      },
    )
  }
  const { deleted } = await deleteWorkCategory(Number(categoryId))
  return { deleted }
}

export async function saveAdminWorkerLevel(payload: JsonObject = {}) {
  const now = nowIso()
  const levelKey = String(payload.levelKey || payload.level_key || '').trim() || DEFAULT_LEVEL_KEY
  const existingLevel = await getWorkerLevelByKey(levelKey)
  const existingPermissions = safeParseJson(existingLevel?.permission_json)
  const name = String(payload.name || '').trim() || DEFAULT_LEVEL_NAME
  const permissions = {
    depositFreeAmount: normalizeAmountFen(
      payload.depositFreeAmount ?? payload.depositFreeAmountYuan,
      0,
    ),
    maxActiveOrders: normalizePositiveInteger(payload.maxActiveOrders, 1),
    upgradeThreshold: normalizeInteger(payload.upgradeThreshold, 0),
    autoAcceptWithoutEvidence: normalizeBoolean(
      payload.autoAcceptWithoutEvidence,
      normalizeBoolean(existingPermissions.autoAcceptWithoutEvidence, levelKey === 'vip5'),
    ),
    visibleDelaySeconds: normalizeInteger(payload.visibleDelaySeconds, -1),
  }
  const level = await upsertWorkerLevel({
    levelKey,
    name,
    sortOrder: normalizeInteger(payload.sortOrder, Number(existingLevel?.sort_order || 100)),
    status: String(payload.status || 'active').trim() === 'disabled' ? 'disabled' : 'active',
    permissionJson: JSON.stringify(permissions),
    now,
  })
  return { level: mapWorkerLevel(level) }
}

export async function deleteAdminWorkerLevel(levelId: number | string) {
  const level = await getWorkerLevelById(Number(levelId))
  if (!level) {
    throw createHttpError('等级不存在', {
      statusCode: 404,
      errorCode: 'worker_level_not_found',
    })
  }
  if (level.level_key === DEFAULT_LEVEL_KEY) {
    throw createHttpError('默认等级（VIP1）不可删除', {
      statusCode: 409,
      errorCode: 'worker_level_default_protected',
    })
  }
  const usageCount = await countWorkerLevelUsages(Number(levelId))
  if (usageCount > 0) {
    throw createHttpError(`该等级正在被 ${usageCount} 名打手使用，请先调整打手等级后再删除`, {
      statusCode: 409,
      errorCode: 'worker_level_in_use',
    })
  }
  const { deleted } = await deleteWorkerLevel(Number(levelId))
  return { deleted }
}

export async function listAdminWorkProductRules(query: JsonObject = {}) {
  await ensureWorkerPlatformDefaults()
  const page = normalizePage(query.page)
  const pageSize = normalizePageSize(query.pageSize)
  const enabledValue = String(query.enabled ?? '').trim()
  const enabled = enabledValue
    ? ['true', '1', 'enabled', 'active'].includes(enabledValue.toLowerCase())
    : null
  const keyword = String(query.keyword || '').trim()
  const categoryId = normalizeOptionalId(query.categoryId ?? query.category_id) || 0
  const [{ items, total }, categoryRows] = await Promise.all([
    listWorkProductRulesPage({
      page,
      pageSize,
      enabled,
      keyword,
      categoryId,
    }),
    countWorkProductRulesByCategory({ enabled, keyword }),
  ])
  return {
    items: items.map(mapWorkProductRule),
    pagination: { page, pageSize, total },
    categoryCounts: categoryRows.map((row) => ({
      categoryId: row.categoryId,
      total: row.total,
    })),
  }
}

export function resolveSharingQuantity(
  totalAmount: number,
  fallbackQuantity: number,
  unitReward: number,
): number {
  if (totalAmount > 0 && unitReward > 0) {
    return Math.max(1, Math.round(totalAmount / unitReward))
  }
  return Math.max(1, fallbackQuantity)
}

function hasConfiguredSharingValue(value: unknown) {
  return value !== undefined && value !== null && String(value).trim() !== ''
}

function hasOwnPayload(payload: JsonObject, key: string) {
  return Object.prototype.hasOwnProperty.call(payload, key)
}

export async function saveAdminWorkProductRule(payload: JsonObject = {}) {
  const defaults = await ensureWorkerPlatformDefaults()
  const ruleId = normalizeOptionalId(payload.ruleId ?? payload.rule_id)
  const existingRule = ruleId ? await getWorkProductRuleById(ruleId) : null
  if (ruleId && !existingRule) {
    throw createHttpError('接单模板不存在', {
      statusCode: 404,
      errorCode: 'work_product_rule_not_found',
    })
  }
  const hasLegacyMatchPayload = [
    'match',
    'sellerId',
    'seller_id',
    'itemId',
    'item_id',
    'relItemId',
    'rel_item_id',
    'skuId',
    'sku_id',
    'relSkuId',
    'rel_sku_id',
    'itemTitle',
    'item_title',
    'skuNick',
    'sku_nick',
    'itemTitleMatchType',
    'item_title_match_type',
    'skuNickMatchType',
    'sku_nick_match_type',
  ].some((key) => Object.prototype.hasOwnProperty.call(payload, key))
  const match = hasLegacyMatchPayload
    ? normalizeWorkProductRuleMatch(payload)
    : safeParseJson(existingRule?.match_json)
  const productName = String(
    payload.productName || payload.product_name || payload.skuName || '',
  ).trim()
  const skuCode = String(payload.skuCode || payload.sku_code || '').trim()
  const matchedProductName = String(match.itemTitle || match.skuNick || '').trim()
  if (!productName && !skuCode && !matchedProductName) {
    throw createHttpError('请填写商品名或 SKU', {
      statusCode: 400,
      errorCode: 'work_product_rule_target_required',
    })
  }

  const rewardAmount = normalizeAmountFen(payload.rewardAmount ?? payload.rewardAmountYuan, 0)
  const unitPriceFen =
    payload.unitPrice === undefined && payload.unitPriceYuan === undefined
      ? 0
      : normalizeAmountFen(payload.unitPrice ?? payload.unitPriceYuan, 0)
  const sharingEnabled = normalizeBoolean(payload.sharingEnabled ?? payload.sharing_enabled, false)
  const acceptanceMode = normalizeWorkOrderAcceptanceMode(
    hasOwnPayload(payload, 'acceptanceMode') || hasOwnPayload(payload, 'acceptance_mode')
      ? payload.acceptanceMode || payload.acceptance_mode
      : existingRule?.acceptance_mode,
  )
  if (acceptanceMode === WORK_ORDER_ACCEPTANCE_MODE.FRIEND_GIFT && sharingEnabled) {
    throw createHttpError('好友赠送验收模式不支持拼单，请先关闭拼单', {
      statusCode: 400,
      errorCode: 'work_product_rule_gift_sharing_conflict',
    })
  }
  const hasManualSharingConfig =
    hasConfiguredSharingValue(payload.sharingTotalQuantity ?? payload.sharing_total_quantity) ||
    hasConfiguredSharingValue(payload.sharingUnitReward ?? payload.sharingUnitRewardYuan) ||
    hasConfiguredSharingValue(payload.sharingTotalAmount ?? payload.sharingTotalAmountYuan)
  const sharingAutoFromOrder =
    sharingEnabled &&
    unitPriceFen > 0 &&
    (normalizeBoolean(payload.sharingAutoFromOrder ?? payload.sharing_auto_from_order, false) ||
      !hasManualSharingConfig)
  const hasManualSharingQuantity = hasConfiguredSharingValue(
    payload.sharingTotalQuantity ?? payload.sharing_total_quantity,
  )
  const hasManualSharingUnitReward = hasConfiguredSharingValue(
    payload.sharingUnitReward ?? payload.sharingUnitRewardYuan,
  )
  if (
    sharingEnabled &&
    unitPriceFen > 0 &&
    !sharingAutoFromOrder &&
    hasManualSharingQuantity !== hasManualSharingUnitReward
  ) {
    throw createHttpError('按件计价的拼单覆盖值请同时填写拼单数量和拼单单价', {
      statusCode: 400,
      errorCode: 'work_product_rule_sharing_override_incomplete',
    })
  }
  const sharingUnitReward = normalizeAmountFen(
    payload.sharingUnitReward ?? payload.sharingUnitRewardYuan,
    0,
  )
  const sharingTotalAmount = normalizeAmountFen(
    payload.sharingTotalAmount ?? payload.sharingTotalAmountYuan,
    0,
  )
  const sharingTotalQuantity = resolveSharingQuantity(
    sharingTotalAmount,
    normalizePositiveInteger(payload.sharingTotalQuantity ?? payload.sharing_total_quantity, 1),
    sharingUnitReward,
  )
  const resolvedSharingTotalAmount =
    sharingTotalAmount > 0 ? sharingTotalAmount : sharingUnitReward * sharingTotalQuantity
  if (sharingEnabled && !sharingAutoFromOrder) {
    if (resolvedSharingTotalAmount <= 0) {
      throw createHttpError('启用拼单时请填写拼单总价或单价', {
        statusCode: 400,
        errorCode: 'work_product_rule_sharing_amount_invalid',
      })
    }
  }
  const finalRewardAmount = sharingEnabled
    ? sharingAutoFromOrder
      ? 0
      : resolvedSharingTotalAmount
    : rewardAmount
  const fields = normalizeRequirementFieldsFromPayload(payload)
  const ruleKey = existingRule?.rule_key || randomId('rule-')
  const rule = await upsertWorkProductRule({
    ruleKey,
    provider: hasOwnPayload(payload, 'provider')
      ? String(payload.provider || '').trim()
      : String(existingRule?.provider || '').trim(),
    platform: hasOwnPayload(payload, 'platform')
      ? String(payload.platform || '').trim()
      : String(existingRule?.platform || '').trim(),
    shopId:
      hasOwnPayload(payload, 'shopId') || hasOwnPayload(payload, 'shop_id')
        ? String(payload.shopId || payload.shop_id || '').trim()
        : String(existingRule?.shop_id || '').trim(),
    skuCode:
      hasOwnPayload(payload, 'skuCode') || hasOwnPayload(payload, 'sku_code')
        ? skuCode
        : String(existingRule?.sku_code || '').trim(),
    productName: productName || matchedProductName,
    matchType:
      hasOwnPayload(payload, 'matchType') || hasOwnPayload(payload, 'match_type')
        ? normalizeMatchType(payload.matchType || payload.match_type)
        : normalizeMatchType(existingRule?.match_type),
    categoryId:
      normalizeOptionalId(payload.categoryId || payload.category_id) ||
      defaults.category?.id ||
      null,
    enabled: normalizeBoolean(payload.enabled, true),
    autoCreate: normalizeBoolean(payload.autoCreate ?? payload.auto_create, true),
    rewardAmount: finalRewardAmount,
    unitPriceFen,
    // 商品规则不配置押金；工单创建后由运营按需手工填写。
    requiredDepositAmount: 0,
    depositThresholdAmount: 0,
    sharingEnabled,
    sharingTotalQuantity,
    sharingUnitReward,
    sharingAutoFromOrder,
    timeoutMinutes: Math.max(0, normalizeInteger(payload.timeoutMinutes, 0)),
    timeoutPolicy: normalizeWorkOrderTimeoutPolicy(payload.timeoutPolicy),
    acceptanceMode,
    giftCooldownHours:
      hasOwnPayload(payload, 'giftCooldownHours') || hasOwnPayload(payload, 'gift_cooldown_hours')
        ? normalizeWorkOrderGiftCooldownHours(
            payload.giftCooldownHours ?? payload.gift_cooldown_hours,
          )
        : normalizeWorkOrderGiftCooldownHours(existingRule?.gift_cooldown_hours),
    giftCooldownMinutes:
      hasOwnPayload(payload, 'giftCooldownMinutes') ||
      hasOwnPayload(payload, 'gift_cooldown_minutes')
        ? normalizeWorkOrderGiftCooldownMinutes(
            payload.giftCooldownMinutes ?? payload.gift_cooldown_minutes,
          )
        : normalizeWorkOrderGiftCooldownMinutes(existingRule?.gift_cooldown_minutes),
    requirementJson: JSON.stringify({ fields }),
    matchJson: JSON.stringify(match),
    sortOrder: normalizeInteger(payload.sortOrder, 100),
    now: nowIso(),
  })
  return { rule: mapWorkProductRule(rule) }
}

/** 根据工单创建时的规格，计算当前模板可同步的价格。 */
export function resolveWorkOrderTemplateSyncPrice(input: {
  rule: WorkProductRuleRow
  workOrder: WorkOrderRow
}): { rewardAmount: number; sharingUnitReward?: number } | null {
  const material = safeParseJson(input.workOrder.material_json)
  const source = safeParseJson(material.source)
  const sourceSkuQuantity = Number(source.skuQuantity || 0)
  const skuQuantity =
    Number.isSafeInteger(sourceSkuQuantity) && sourceSkuQuantity > 0
      ? sourceSkuQuantity
      : resolveSkuNameQuantity(input.workOrder.product_name)
  const pricing = resolveWorkOrderRulePricing({
    skuQuantity,
    unitPriceFen: Number(input.rule.unit_price_fen || 0),
    fixedRewardAmount: Number(input.rule.reward_amount || 0),
    sharingEnabled: input.rule.sharing_enabled === true,
    sharingAutoFromOrder: input.rule.sharing_auto_from_order === true,
    sharingTotalQuantity: Number(input.rule.sharing_total_quantity || 1),
    sharingUnitReward: Number(input.rule.sharing_unit_reward || 0),
  })

  if (input.workOrder.sharing_enabled === true) {
    if (input.rule.sharing_enabled !== true || pricing.sharingUnitReward <= 0) {
      return null
    }
    return {
      rewardAmount: pricing.rewardAmount,
      sharingUnitReward: pricing.sharingUnitReward,
    }
  }
  return pricing.rewardAmount > 0 ? { rewardAmount: pricing.rewardAmount } : null
}

/** 将指定模板的当前价格同步到仍在接单大厅的来源工单。 */
export async function syncAdminWorkProductRulePrice(ruleId: number | string, actorName = '') {
  const normalizedRuleId = normalizeOptionalId(ruleId)
  const rule = normalizedRuleId ? await getWorkProductRuleById(normalizedRuleId) : null
  if (!rule) {
    throw createHttpError('接单模板不存在', {
      statusCode: 404,
      errorCode: 'work_product_rule_not_found',
    })
  }

  const candidates = await listOpenWorkOrdersByProductRuleId(rule.id)
  const result = {
    candidateCount: candidates.length,
    updatedCount: 0,
    updatedNormalCount: 0,
    updatedPartialSharingCount: 0,
    skippedInvalidPricingCount: 0,
    skippedUnchangedCount: 0,
    skippedUnavailableCount: 0,
  }
  const now = nowIso()

  for (const workOrder of candidates) {
    const price = resolveWorkOrderTemplateSyncPrice({ rule, workOrder })
    if (!price) {
      result.skippedInvalidPricingCount += 1
      continue
    }
    const synced = await syncOpenWorkOrderPriceFromRule({
      workOrderId: Number(workOrder.id),
      productRuleId: Number(rule.id),
      rewardAmount: price.rewardAmount,
      ...(price.sharingUnitReward === undefined
        ? {}
        : { sharingUnitReward: price.sharingUnitReward }),
      actorName,
      now,
    })
    if (!synced.updated) {
      if (synced.reason === 'price_unchanged') {
        result.skippedUnchangedCount += 1
      } else {
        result.skippedUnavailableCount += 1
      }
      continue
    }
    result.updatedCount += 1
    if (synced.sharingPartial) {
      result.updatedPartialSharingCount += 1
    } else {
      result.updatedNormalCount += 1
    }
    publishWorkOrderRealtimeChange({
      workOrderId: synced.workOrderId,
      workerIds: synced.workerIds,
      hallChanged: true,
    })
  }

  return { rule: mapWorkProductRule(rule), ...result }
}

export async function deleteAdminWorkProductRule(ruleId: number | string) {
  const normalizedRuleId = normalizeOptionalId(ruleId)
  if (!normalizedRuleId) {
    throw createHttpError('物品规则 ID 不正确', {
      statusCode: 400,
      errorCode: 'work_product_rule_id_invalid',
    })
  }
  const { deleted } = await deleteWorkProductRule(normalizedRuleId)
  if (!deleted) {
    throw createHttpError('物品规则不存在或已删除', {
      statusCode: 404,
      errorCode: 'work_product_rule_not_found',
    })
  }
  return { deleted }
}
