const cloud = require('wx-server-sdk')

cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV })
const db = cloud.database()
const _ = db.command
const SERVER_MESSAGE_LIMIT = 50

function timeText(ts) {
  if (!ts) return ''
  const d = new Date(ts)
  const hh = String(d.getHours()).padStart(2, '0')
  const mm = String(d.getMinutes()).padStart(2, '0')
  const sameDay = new Date().toDateString() === d.toDateString()
  if (sameDay) return `${hh}:${mm}`
  return `${d.getMonth() + 1}/${d.getDate()} ${hh}:${mm}`
}

async function userToPeer(u) {
  return { id: u._id, name: u.nickname || '用户', avatarKey: u.avatarKey || 'gradient-avatar-1', avatarUrl: u.avatarUrl || '' }
}

function normalizeLimit(value) {
  const limit = Number(value || SERVER_MESSAGE_LIMIT)
  if (!Number.isFinite(limit)) return SERVER_MESSAGE_LIMIT
  return Math.max(1, Math.min(Math.floor(limit), SERVER_MESSAGE_LIMIT))
}

function messageToClient(m, openid) {
  return {
    _id: m._id,
    fromMe: m.fromOpenid === openid,
    content: m.content,
    type: m.type || 'text',
    createdAt: m.createdAt,
    timeText: timeText(m.createdAt)
  }
}

exports.main = async event => {
  const { OPENID } = cloud.getWXContext()
  if (!OPENID) throw new Error('no openid in wx context')

  let convId = event.conversationId || ''
  let peer = null
  const pageSize = normalizeLimit(event.pageSize || event.limit)

  // Open by target user — resolve peer and find an existing conversation.
  if (!convId && event.targetUserId) {
    const tRes = await db.collection('users').doc(event.targetUserId).get().catch(() => null)
    const t = tRes && tRes.data
    if (t) {
      peer = await userToPeer(t)
      const ex = await db.collection('conversations')
        .where({ type: 'single', memberOpenids: _.all([OPENID, t.openid]) })
        .limit(1)
        .get()
        .catch(() => ({ data: [] }))
      if (ex.data.length) convId = ex.data[0]._id
    }
  }

  // Open by conversation — resolve the other member as peer.
  if (convId && !peer) {
    const c = await db.collection('conversations').doc(convId).get().catch(() => null)
    if (c && c.data) {
      const otherOpenid = (c.data.memberOpenids || []).find(o => o !== OPENID)
      if (otherOpenid) {
        const oRes = await db.collection('users').where({ openid: otherOpenid }).limit(1).get()
        if (oRes.data[0]) peer = await userToPeer(oRes.data[0])
      }
      if (!peer) {
        peer = { id: '', name: c.data.title || '对话', avatarKey: c.data.avatarKey || 'gradient-avatar-1', avatarUrl: '' }
      }
    }
  }

  let messages = []
  let nextCursor = ''
  if (convId) {
    const query = { conversationId: convId }
    const cursor = Number(event.cursor || 0)
    if (Number.isFinite(cursor) && cursor > 0) query.createdAt = _.lt(cursor)

    const res = await db.collection('messages')
      .where(query)
      .orderBy('createdAt', 'desc')
      .limit(pageSize + 1)
      .get()
      .catch(() => ({ data: [] }))
    const page = res.data.slice(0, pageSize)
    messages = page.reverse().map(m => messageToClient(m, OPENID))
    if (res.data.length > pageSize && messages[0]) {
      nextCursor = String(messages[0].createdAt || '')
    }

    // Mark this conversation read for me only when the client asks for it.
    // Silent polling and loading older history should not write the conversation.
    if (event.markRead !== false) {
      await db.collection('conversations').doc(convId).update({
        data: { unreadOpenids: _.pull(OPENID), [`unreadCounts.${OPENID}`]: 0 }
      }).catch(() => {})
    }
  }

  return { conversationId: convId, peer, messages, nextCursor }
}
