const crypto = require('crypto')
const AppError = require('../utils/appError')
const logger = require('../utils/logger')
const wechatService = require('./wechatService')
const jwtService = require('./jwtService')
const pocketbaseService = require('./pocketbaseService')

const userMutationLocks = new Map()
const GUEST_USER_TYPE = '游客'
const REGISTERED_USER_TYPE = '注册用户'

function buildUserId() {
    const now = new Date()
    const date = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}${String(now.getDate()).padStart(2, '0')}`
    const suffix = crypto.randomInt(1000, 9999)
    return `U${date}${suffix}`
}

async function enrichUser(user) {
    const company = await pocketbaseService.getCompanyByCompanyId(user.company_id)
    return {
        pb_id: user.id,
        users_id: user.users_id,
        users_type: user.users_type || GUEST_USER_TYPE,
        users_name: user.users_name,
        users_phone: user.users_phone,
        users_phone_masked: maskPhone(user.users_phone),
        users_picture: user.users_picture,
        users_wx_openid: user.users_wx_openid,
        company_id: user.company_id || '',
        company,
        created: user.created,
        updated: user.updated,
        raw: user,
    }
}

async function findUserByOpenid(usersWxOpenid) {
    const users = await pocketbaseService.listUsersByFilter(`users_wx_openid = "${usersWxOpenid}"`)
    return users[0] || null
}

function maskPhone(phone = '') {
    if (!phone || phone.length < 7) return ''
    return `${phone.slice(0, 3)}****${phone.slice(-4)}`
}

function isInfoComplete(user = {}) {
    return Boolean(user.users_name && user.users_phone && user.users_picture)
}

function isAllProfileFieldsEmpty(user = {}) {
    return !user.users_name && !user.users_phone && !user.users_picture
}

async function withUserLock(lockKey, handler) {
    const previous = userMutationLocks.get(lockKey) || Promise.resolve()
    let release
    const current = new Promise((resolve) => {
        release = resolve
    })

    userMutationLocks.set(lockKey, previous.then(() => current))

    await previous

    try {
        return await handler()
    } finally {
        release()
        if (userMutationLocks.get(lockKey) === current) {
            userMutationLocks.delete(lockKey)
        }
    }
}

async function authenticateWechatUser(payload) {
    const openid = await wechatService.getWxOpenId(payload.users_wx_code)
    return withUserLock(`auth:${openid}`, async () => {
        const existing = await findUserByOpenid(openid)

        if (existing) {
            logger.warn('微信注册命中已存在账号', {
                users_wx_openid: openid,
                users_type: existing.users_type || GUEST_USER_TYPE,
            })

            const user = await enrichUser(existing)
            const token = jwtService.signAccessToken({
                users_id: user.users_id,
                users_wx_openid: user.users_wx_openid,
            })

            return {
                status: 'login_success',
                is_info_complete: isInfoComplete(existing),
                token,
                user,
            }
        }

        const created = await pocketbaseService.createUser({
            users_id: buildUserId(),
            users_wx_openid: openid,
            users_type: GUEST_USER_TYPE,
        })

        const user = await enrichUser(created)
        const token = jwtService.signAccessToken({
            users_id: user.users_id,
            users_wx_openid: user.users_wx_openid,
        })

        logger.info('微信用户注册成功', {
            users_id: user.users_id,
            users_phone: user.users_phone,
            users_type: user.users_type,
        })

        return {
            status: 'register_success',
            is_info_complete: false,
            token,
            user,
        }
    })
}

async function updateWechatUserProfile(usersWxOpenid, payload) {
    return withUserLock(`profile:${usersWxOpenid}`, async () => {
        const currentUser = await findUserByOpenid(usersWxOpenid)

        if (!currentUser) {
            throw new AppError('未找到待编辑的用户', 404)
        }

        const usersPhone = await wechatService.getWxPhoneNumber(payload.users_phone_code)

        if (usersPhone && usersPhone !== currentUser.users_phone) {
            const samePhoneUsers = await pocketbaseService.listUsersByFilter(`users_phone = "${usersPhone}"`)
            const phoneUsedByOther = samePhoneUsers.some((item) => item.id !== currentUser.id)
            if (phoneUsedByOther) {
                throw new AppError('手机号已被注册', 400)
            }
        }

        const shouldPromoteUserType =
            isAllProfileFieldsEmpty(currentUser)
            && payload.users_name
            && usersPhone
            && payload.users_picture
            && (currentUser.users_type === GUEST_USER_TYPE || !currentUser.users_type)

        const updatePayload = {
            users_name: payload.users_name,
            users_phone: usersPhone,
            users_picture: payload.users_picture,
        }

        if (shouldPromoteUserType) {
            updatePayload.users_type = REGISTERED_USER_TYPE
        }

        const updated = await pocketbaseService.updateUser(currentUser.id, updatePayload)
        const user = await enrichUser(updated)

        logger.info('微信用户资料更新成功', {
            users_id: user.users_id,
            users_phone: user.users_phone,
            users_type_before: currentUser.users_type || GUEST_USER_TYPE,
            users_type_after: user.users_type,
            users_type_promoted: shouldPromoteUserType,
        })

        return {
            status: 'update_success',
            user,
        }
    })
}

async function refreshWechatToken(usersWxOpenid) {
    const userRecord = await findUserByOpenid(usersWxOpenid)

    if (!userRecord) {
        throw new AppError('未注册用户', 404)
    }

    const token = jwtService.signAccessToken({
        users_id: userRecord.users_id,
        users_wx_openid: userRecord.users_wx_openid,
    })

    logger.info('微信用户刷新令牌成功', {
        users_id: userRecord.users_id,
        users_wx_openid: userRecord.users_wx_openid,
    })

    return {
        token,
    }
}

module.exports = {
    authenticateWechatUser,
    updateWechatUserProfile,
    refreshWechatToken,
}
