import {
  countWorkerWithdrawRequestsOnDay,
  createWorkerFinanceRequest,
  createWorkerWithdrawRequestWithFreeze,
  getWorkerWithdrawalAccount,
  listDueDepositUnfreezes,
  releaseDepositUnfreeze,
} from '../../repositories/worker-platform/index.js'
import type { JsonObject } from '../../types/json.js'
import { createHttpError } from '../../utils/http.js'
import { nowIso } from '../../utils/time.js'
import {
  createWorkerRechargeAdminNotification,
  createWorkerWithdrawAdminNotification,
} from '../admin/admin-notification-service.js'
import {
  publishWorkerFinanceRealtimeChange,
  publishWorkerWalletRealtimeChange,
} from '../realtime/realtime-event-service.js'
import {
  assertWithdrawChannelAllowedForAmount,
  mapFinanceRequest,
  normalizeAmountFen,
  normalizeProofFiles,
  normalizeWithdrawChannel,
} from './mappers.js'
import { getWorkerFinanceConfig } from './worker-finance-config-service.js'
import {
  resolveAlipayWithdrawalQrCode,
  resolveWechatWithdrawalQrCode,
} from './worker-withdrawal-account-service.js'
import {
  getRequiredWorker,
  requireActiveWorkerSession,
  type WorkerSession,
} from './worker-session-context-service.js'

const WORKER_DAILY_WITHDRAW_LIMIT = 3

export async function createWorkerRechargeRequest(
  payload: JsonObject = {},
  session: WorkerSession,
) {
  requireActiveWorkerSession(session)
  const worker = await getRequiredWorker(session.workerId)
  const financeConfig = getWorkerFinanceConfig()
  if (financeConfig.recharge.enabled === false) {
    throw createHttpError('当前充值入口暂未开放，请联系管理员', {
      statusCode: 409,
      errorCode: 'worker_recharge_disabled',
    })
  }
  const amount = normalizeAmountFen(payload.amount ?? payload.amountYuan, 0)
  if (amount <= 0) {
    throw createHttpError('充值金额必须大于 0', {
      statusCode: 400,
      errorCode: 'worker_recharge_amount_invalid',
    })
  }

  const note = String(payload.note || payload.remark || '').trim()
  const proofFiles = normalizeProofFiles(payload.proofFiles || payload.proofFilesList)
  const paidAt = String(payload.paidAt || '').trim()
  const created = await createWorkerFinanceRequest({
    workerId: worker.id,
    requestType: 'recharge',
    amount,
    accountChannel: 'manual',
    accountName: worker.display_name || worker.username,
    accountNo: worker.phone || '',
    note: note || '个人中心充值申请',
    payloadJson: JSON.stringify({
      source: 'worker_profile_recharge',
      username: worker.username,
      phone: worker.phone || '',
      paidAt: paidAt || null,
      proofFiles,
      financeConfig: {
        channelName: financeConfig.recharge.channelName,
        accountName: financeConfig.recharge.accountName,
        accountNo: financeConfig.recharge.accountNo,
        qrCodeImage: financeConfig.recharge.qrCodeImage,
      },
    }),
    now: nowIso(),
  })
  if (!created) {
    throw createHttpError('充值申请创建失败', {
      statusCode: 500,
      errorCode: 'worker_recharge_request_create_failed',
    })
  }
  await createWorkerRechargeAdminNotification({
    requestId: Number(created.id),
    workerName: worker.display_name || worker.username,
    amountFen: Number(created.amount || amount),
  })
  publishWorkerFinanceRealtimeChange({
    requestId: Number(created.id),
    workerId: Number(worker.id),
  })
  return {
    request: mapFinanceRequest(created),
  }
}

export async function createWorkerWithdrawRequest(
  payload: JsonObject = {},
  session: WorkerSession,
) {
  requireActiveWorkerSession(session)
  const worker = await getRequiredWorker(session.workerId)
  const financeConfig = getWorkerFinanceConfig()
  if (financeConfig.withdraw.enabled === false) {
    throw createHttpError('当前提现入口暂未开放，请联系管理员', {
      statusCode: 409,
      errorCode: 'worker_withdraw_disabled',
    })
  }

  await settleDueDepositUnfreezes({ workerId: worker.id, limit: 50 })
  const dayRange = resolveChinaDayRange()
  const withdrawCountToday = await countWorkerWithdrawRequestsOnDay(
    worker.id,
    dayRange.start,
    dayRange.end,
  )
  if (withdrawCountToday >= WORKER_DAILY_WITHDRAW_LIMIT) {
    throw createHttpError('每天最多提现 3 次（支付宝、微信共享次数），今天已达上限', {
      statusCode: 409,
      errorCode: 'worker_withdraw_daily_limit_reached',
    })
  }

  const amount = normalizeAmountFen(payload.amount ?? payload.amountYuan, 0)
  if (amount <= 0) {
    throw createHttpError('提现金额必须大于 0', {
      statusCode: 400,
      errorCode: 'worker_withdraw_amount_invalid',
    })
  }

  const accountChannel = normalizeWithdrawChannel(payload.accountChannel || payload.channel)
  const withdrawalAccount = await getWorkerWithdrawalAccount(worker.id, accountChannel)
  if (!withdrawalAccount) {
    throw createHttpError('请先添加对应的提现信息；修改提现信息请联系客服处理', {
      statusCode: 409,
      errorCode: 'worker_withdrawal_account_required',
    })
  }
  assertWithdrawChannelAllowedForAmount(amount, accountChannel)
  const alipayQrCodeImage = resolveAlipayWithdrawalQrCode(withdrawalAccount)
  const wechatQrCodeImage = resolveWechatWithdrawalQrCode(withdrawalAccount)
  if (accountChannel === 'alipay' && !alipayQrCodeImage) {
    throw createHttpError('支付宝提现信息缺少收款二维码，请先补充后再提现', {
      statusCode: 409,
      errorCode: 'worker_withdrawal_alipay_qr_required',
    })
  }
  if (accountChannel === 'wechat' && !wechatQrCodeImage) {
    throw createHttpError('微信提现信息缺少收款二维码，请联系客服处理', {
      statusCode: 409,
      errorCode: 'worker_withdrawal_wechat_qr_required',
    })
  }

  const note = String(payload.note || payload.remark || '').trim()
  const created = await createWorkerWithdrawRequestWithFreeze({
    workerId: worker.id,
    amount,
    accountChannel,
    accountName: withdrawalAccount.account_name,
    accountNo: withdrawalAccount.account_no,
    note: note || '个人中心提现申请',
    payloadJson: JSON.stringify({
      source: 'worker_profile_withdraw',
      username: worker.username,
      phone: worker.phone || '',
      alipayQrCodeImage,
      wechatQrCodeImage,
    }),
    now: nowIso(),
  })
  if (created.failureReason === 'withdraw_insufficient') {
    throw createHttpError('可提现余额不足，请先减少提现金额或等待已提交申请处理', {
      statusCode: 409,
      errorCode: 'worker_withdraw_amount_insufficient',
    })
  }
  const request = created.request
  await createWorkerWithdrawAdminNotification({
    requestId: Number(request.id),
    workerName: worker.display_name || worker.username,
    amountFen: Number(request.amount || amount),
    channel: request.account_channel,
  })
  publishWorkerFinanceRealtimeChange({
    requestId: Number(request.id),
    workerId: Number(worker.id),
  })
  publishWorkerWalletRealtimeChange(Number(worker.id))
  return {
    request: mapFinanceRequest(request),
    availableForWithdraw: Math.max(
      0,
      Number(worker.available_amount || 0) - Number(request.amount || amount),
    ),
  }
}

export async function settleDueDepositUnfreezes(
  options: { limit?: number; workerId?: number } = {},
) {
  // 到期判定按当前解冻天数回溯：管理员调小财务配置后，存量待解冻按新天数提前视为到期，
  // 否则入队时的旧天数会让"扫描 0 笔"一直持续到原到期时间。
  const retroactiveDays = getWorkerFinanceConfig().depositUnfreezeDays
  const due = await listDueDepositUnfreezes({
    limit: Math.max(1, Number(options.limit || 100)),
    workerId: Number(options.workerId || 0),
    retroactiveDays,
  })
  let processedCount = 0
  for (const unfreeze of due) {
    const released = await releaseDepositUnfreeze({
      unfreezeId: unfreeze.id,
      now: nowIso(),
    })
    if (released) {
      processedCount += 1
      publishWorkerWalletRealtimeChange(Number(released.worker_id))
    }
  }
  return {
    checkedCount: due.length,
    processedCount,
  }
}

function resolveChinaDayRange(): { start: string; end: string } {
  const utcNow = new Date()
  const utcDayStartMs =
    Date.UTC(utcNow.getUTCFullYear(), utcNow.getUTCMonth(), utcNow.getUTCDate()) - 8 * 3_600_000
  return {
    start: new Date(utcDayStartMs).toISOString(),
    end: new Date(utcDayStartMs + 86_400_000).toISOString(),
  }
}
