const env = require(`${__hooks}/bai_api_pb_hooks/bai_api_shared/config/env.js`)
const { createAppError } = require(`${__hooks}/bai_api_pb_hooks/bai_api_shared/utils/appError.js`)

const ROLE_COLLECTION = 'tbl_auth_roles'
const USER_COLLECTION = 'tbl_auth_users'
const MANAGE_PLATFORM_EXPR = '@request.auth.users_idtype = "ManagePlatform"'
const AUTHENTICATED_EXPR = '@request.auth.id != ""'
const RULE_KEYS = ['listRule', 'viewRule', 'createRule', 'updateRule', 'deleteRule']

function parseJsonResponse(response, actionName) {
    if (!response) {
        throw createAppError(500, actionName + ' 失败：PocketBase 响应为空')
    }

    if (response.json && typeof response.json === 'object') {
        return response.json
    }

    if (typeof response.body === 'string' && response.body) {
        return JSON.parse(response.body)
    }

    if (response.body && typeof response.body === 'object') {
        return response.body
    }

    if (typeof response.data === 'string' && response.data) {
        return JSON.parse(response.data)
    }

    if (response.data && typeof response.data === 'object') {
        return response.data
    }

    return {}
}

function getPocketBaseApiBaseUrl() {
    const base = String(env.pocketbaseApiUrl || '').replace(/\/+$/, '')
    if (!base) {
        throw createAppError(500, '缺少 POCKETBASE_API_URL 配置，无法同步 PocketBase collection rules')
    }
    return base
}

function getPocketBaseAuthToken() {
    const token = String(env.pocketbaseAuthToken || '').trim()
    if (!token) {
        throw createAppError(500, '缺少 POCKETBASE_AUTH_TOKEN 配置，无法同步 PocketBase collection rules')
    }
    return token
}

function requestPocketBase(method, path, body, actionName) {
    const baseUrl = getPocketBaseApiBaseUrl()
    const token = getPocketBaseAuthToken()
    const headers = {
        Authorization: 'Bearer ' + token,
    }

    if (body) {
        headers['Content-Type'] = 'application/json'
    }

    const response = $http.send({
        url: baseUrl + path,
        method: method,
        headers: headers,
        body: body ? JSON.stringify(body) : '',
    })

    if (!response || response.statusCode < 200 || response.statusCode >= 300) {
        throw createAppError(500, actionName + ' 失败', {
            statusCode: response ? response.statusCode : 0,
            body: response ? String(response.body || '') : '',
        })
    }

    return parseJsonResponse(response, actionName)
}

function buildRoleId() {
    return 'ROLE-' + new Date().getTime() + '-' + $security.randomString(6)
}

function normalizeText(value) {
    return String(value || '').replace(/^\s+|\s+$/g, '')
}

function uniqueList(values) {
    const result = []
    for (let i = 0; i < (values || []).length; i += 1) {
        const current = normalizeText(values[i])
        if (current && result.indexOf(current) === -1) {
            result.push(current)
        }
    }
    return result
}

function listRoles() {
    const records = $app.findRecordsByFilter(ROLE_COLLECTION, '', 'role_name', 500, 0)

    return records.map(function (record) {
        return {
            pb_id: record.id,
            role_id: record.getString('role_id'),
            role_name: record.getString('role_name'),
            role_code: record.getString('role_code'),
            role_status: record.get('role_status'),
            role_remark: record.getString('role_remark'),
            created: String(record.created || ''),
            updated: String(record.updated || ''),
        }
    })
}

function buildRoleMap(roles) {
    const map = {}
    for (let i = 0; i < (roles || []).length; i += 1) {
        const role = roles[i]
        if (role && role.role_id) {
            map[role.role_id] = role
        }
    }
    return map
}

function findRoleRecordByRoleId(roleId) {
    const value = normalizeText(roleId)
    if (!value) return null

    const records = $app.findRecordsByFilter(ROLE_COLLECTION, 'role_id = {:roleId}', '', 1, 0, {
        roleId: value,
    })
    return records.length ? records[0] : null
}

function saveRole(payload) {
    const roleId = normalizeText(payload.role_id) || buildRoleId()
    const originalRoleId = normalizeText(payload.original_role_id || roleId)
    const roleName = normalizeText(payload.role_name)

    if (!roleName) {
        throw createAppError(400, 'role_name 为必填项')
    }

    let record = findRoleRecordByRoleId(originalRoleId)
    if (!record) {
        const collection = $app.findCollectionByNameOrId(ROLE_COLLECTION)
        record = new Record(collection)
        record.set('role_id', roleId)
    }

    const sameIdRecord = findRoleRecordByRoleId(roleId)
    if (sameIdRecord && sameIdRecord.id !== record.id) {
        throw createAppError(400, 'role_id 已存在')
    }

    record.set('role_id', roleId)
    record.set('role_name', roleName)
    record.set('role_code', normalizeText(payload.role_code))
    record.set('role_status', Number(payload.role_status || 1))
    record.set('role_remark', normalizeText(payload.role_remark))

    try {
        $app.save(record)
    } catch (err) {
        throw createAppError(400, '保存角色失败', {
            originalMessage: (err && err.message) || '未知错误',
            originalData: (err && err.data) || {},
        })
    }

    return {
        role: {
            pb_id: record.id,
            role_id: record.getString('role_id'),
            role_name: record.getString('role_name'),
            role_code: record.getString('role_code'),
            role_status: record.get('role_status'),
            role_remark: record.getString('role_remark'),
            created: String(record.created || ''),
            updated: String(record.updated || ''),
        },
    }
}

function buildRuleParts(config) {
    const parts = []
    if (config.includeManagePlatform) {
        parts.push(MANAGE_PLATFORM_EXPR)
    }
    if (config.mode === 'authenticated') {
        parts.push(AUTHENTICATED_EXPR)
    }
    if (config.mode === 'roleBased') {
        const roles = uniqueList(config.roles || [])
        for (let i = 0; i < roles.length; i += 1) {
            parts.push('@request.auth.usergroups_id = "' + roles[i].replace(/"/g, '\\"') + '"')
        }
    }
    return uniqueList(parts)
}

function buildRuleExpression(config) {
    const mode = normalizeText(config.mode)

    if (mode === 'public') {
        return ''
    }

    if (mode === 'custom') {
        const raw = normalizeText(config.rawExpression)
        if (!raw) {
            return config.includeManagePlatform ? MANAGE_PLATFORM_EXPR : null
        }
        if (config.includeManagePlatform && raw.indexOf(MANAGE_PLATFORM_EXPR) === -1) {
            return '(' + raw + ') || ' + MANAGE_PLATFORM_EXPR
        }
        return raw
    }

    if (mode === 'locked') {
        return null
    }

    const parts = buildRuleParts(config)
    return parts.length ? parts.join(' || ') : null
}

function parseRuleExpression(ruleValue) {
    if (typeof ruleValue === 'undefined' || ruleValue === null) {
        return {
            mode: 'locked',
            includeManagePlatform: false,
            roles: [],
            rawExpression: '',
        }
    }

    const expression = String(ruleValue)
    if (expression === '') {
        return {
            mode: 'public',
            includeManagePlatform: false,
            roles: [],
            rawExpression: '',
        }
    }

    const includeManagePlatform = expression.indexOf(MANAGE_PLATFORM_EXPR) !== -1
    const includeAuthenticated = expression.indexOf(AUTHENTICATED_EXPR) !== -1
    const roles = []
    const roleRegex = /@request\.auth\.usergroups_id\s*=\s*"([^"]+)"/g
    let match = roleRegex.exec(expression)
    while (match) {
        roles.push(match[1])
        match = roleRegex.exec(expression)
    }

    const cleaned = expression
        .replace(new RegExp(MANAGE_PLATFORM_EXPR.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), '')
        .replace(new RegExp(AUTHENTICATED_EXPR.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'), '')
        .replace(roleRegex, '')
        .replace(/\s*\|\|\s*/g, '')
        .replace(/^\s+|\s+$/g, '')

    if (cleaned) {
        return {
            mode: 'custom',
            includeManagePlatform: includeManagePlatform,
            roles: uniqueList(roles),
            rawExpression: expression,
        }
    }

    if (includeAuthenticated && !roles.length) {
        return {
            mode: 'authenticated',
            includeManagePlatform: includeManagePlatform,
            roles: [],
            rawExpression: '',
        }
    }

    return {
        mode: 'roleBased',
        includeManagePlatform: includeManagePlatform,
        roles: uniqueList(roles),
        rawExpression: '',
    }
}

function listManageableCollections() {
    const data = requestPocketBase('GET', '/api/collections?page=1&perPage=200&sort=name', null, '查询集合列表')
    const items = Array.isArray(data.items) ? data.items : []

    return items
        .filter(function (item) {
            return !item.system && item.type !== 'view' && String(item.name || '').indexOf('_') !== 0
        })
        .map(function (item) {
            return {
                id: item.id,
                name: item.name,
                type: item.type,
                listRule: item.listRule,
                viewRule: item.viewRule,
                createRule: item.createRule,
                updateRule: item.updateRule,
                deleteRule: item.deleteRule,
                parsedRules: {
                    list: parseRuleExpression(item.listRule),
                    view: parseRuleExpression(item.viewRule),
                    create: parseRuleExpression(item.createRule),
                    update: parseRuleExpression(item.updateRule),
                    delete: parseRuleExpression(item.deleteRule),
                },
            }
        })
}

function saveCollectionRules(payload) {
    const collectionName = normalizeText(payload.collection_name)
    if (!collectionName) {
        throw createAppError(400, 'collection_name 为必填项')
    }

    const collections = listManageableCollections()
    const target = collections.find(function (item) {
        return item.name === collectionName
    })
    if (!target) {
        throw createAppError(404, '未找到可管理的集合：' + collectionName)
    }

    const rulesPayload = {
        listRule: buildRuleExpression(payload.rules && payload.rules.list ? payload.rules.list : { mode: 'locked' }),
        viewRule: buildRuleExpression(payload.rules && payload.rules.view ? payload.rules.view : { mode: 'locked' }),
        createRule: buildRuleExpression(payload.rules && payload.rules.create ? payload.rules.create : { mode: 'locked' }),
        updateRule: buildRuleExpression(payload.rules && payload.rules.update ? payload.rules.update : { mode: 'locked' }),
        deleteRule: buildRuleExpression(payload.rules && payload.rules.delete ? payload.rules.delete : { mode: 'locked' }),
    }

    requestPocketBase('PATCH', '/api/collections/' + encodeURIComponent(target.id), rulesPayload, '保存集合权限')

    return {
        collection: listManageableCollections().find(function (item) {
            return item.name === collectionName
        }) || null,
    }
}

function listUsers(keyword, roleMap) {
    const search = normalizeText(keyword).toLowerCase()
    const records = $app.findRecordsByFilter(USER_COLLECTION, '', '-users_id', 500, 0)
    const items = records.map(function (record) {
        const usergroupsId = record.getString('usergroups_id')
        const role = roleMap && roleMap[usergroupsId] ? roleMap[usergroupsId] : null
        return {
            pb_id: record.id,
            users_id: record.getString('users_id'),
            users_name: record.getString('users_name'),
            users_phone: record.getString('users_phone'),
            openid: record.getString('openid'),
            users_idtype: record.getString('users_idtype'),
            users_type: record.getString('users_type'),
            users_status: record.get('users_status'),
            users_rank_level: record.get('users_rank_level'),
            usergroups_id: usergroupsId,
            role_name: role ? role.role_name : '',
            created: String(record.created || ''),
            updated: String(record.updated || ''),
        }
    })

    if (!search) {
        return items
    }

    return items.filter(function (item) {
        return String(item.users_name || '').toLowerCase().indexOf(search) !== -1
            || String(item.users_phone || '').toLowerCase().indexOf(search) !== -1
            || String(item.openid || '').toLowerCase().indexOf(search) !== -1
            || String(item.role_name || '').toLowerCase().indexOf(search) !== -1
    })
}

function updateUserRole(payload) {
    const userId = normalizeText(payload.pb_id)
    if (!userId) {
        throw createAppError(400, 'pb_id 为必填项')
    }

    const collection = $app.findCollectionByNameOrId(USER_COLLECTION)
    const record = $app.findRecordById(collection, userId)
    if (!record) {
        throw createAppError(404, '未找到对应用户')
    }

    const roleId = normalizeText(payload.usergroups_id)
    if (roleId && !findRoleRecordByRoleId(roleId)) {
        throw createAppError(400, '指定的 role_id 不存在')
    }

    record.set('usergroups_id', roleId)

    try {
        $app.save(record)
    } catch (err) {
        throw createAppError(400, '保存用户角色失败', {
            originalMessage: (err && err.message) || '未知错误',
            originalData: (err && err.data) || {},
        })
    }

    return {
        user: {
            pb_id: record.id,
            users_id: record.getString('users_id'),
            users_name: record.getString('users_name'),
            users_phone: record.getString('users_phone'),
            openid: record.getString('openid'),
            users_idtype: record.getString('users_idtype'),
            users_type: record.getString('users_type'),
            users_status: record.get('users_status'),
            users_rank_level: record.get('users_rank_level'),
            usergroups_id: record.getString('usergroups_id'),
            created: String(record.created || ''),
            updated: String(record.updated || ''),
        },
    }
}

function deleteRole(roleId) {
    const value = normalizeText(roleId)
    if (!value) {
        throw createAppError(400, 'role_id 为必填项')
    }

    const record = findRoleRecordByRoleId(value)
    if (!record) {
        throw createAppError(404, '未找到对应角色')
    }

    const users = $app.findRecordsByFilter(USER_COLLECTION, 'usergroups_id = {:roleId}', '', 500, 0, {
        roleId: value,
    })
    for (let i = 0; i < users.length; i += 1) {
        users[i].set('usergroups_id', '')
        $app.save(users[i])
    }

    const collections = listManageableCollections()
    for (let i = 0; i < collections.length; i += 1) {
        const item = collections[i]
        let changed = false
        const nextRules = {}

        ;['list', 'view', 'create', 'update', 'delete'].forEach(function (operation) {
            const config = item.parsedRules[operation]
            if (!config || config.mode === 'custom') {
                nextRules[operation] = config
                return
            }

            const nextRoles = uniqueList((config.roles || []).filter(function (currentRoleId) {
                return currentRoleId !== value
            }))
            if (nextRoles.length !== (config.roles || []).length) {
                changed = true
            }

            nextRules[operation] = {
                mode: config.mode,
                includeManagePlatform: !!config.includeManagePlatform,
                roles: nextRoles,
                rawExpression: config.rawExpression || '',
            }
        })

        if (changed) {
            saveCollectionRules({
                collection_name: item.name,
                rules: nextRules,
            })
        }
    }

    $app.delete(record)

    return {
        deleted_role_id: value,
    }
}

function syncManagePlatformFullAccess() {
    const collections = listManageableCollections()

    for (let i = 0; i < collections.length; i += 1) {
        const item = collections[i]
        const nextRules = {}

        ;['list', 'view', 'create', 'update', 'delete'].forEach(function (operation) {
            const config = item.parsedRules[operation]
            if (config && config.mode === 'custom') {
                nextRules[operation] = {
                    mode: 'custom',
                    includeManagePlatform: true,
                    roles: config.roles || [],
                    rawExpression: config.rawExpression || '',
                }
                return
            }

            nextRules[operation] = {
                mode: config ? config.mode : 'roleBased',
                includeManagePlatform: true,
                roles: config ? (config.roles || []) : [],
                rawExpression: config ? (config.rawExpression || '') : '',
            }

            if (nextRules[operation].mode === 'locked' && !nextRules[operation].roles.length) {
                nextRules[operation].mode = 'roleBased'
            }
        })

        saveCollectionRules({
            collection_name: item.name,
            rules: nextRules,
        })
    }

    return {
        count: collections.length,
    }
}

function getManagementContext(keyword) {
    const roles = listRoles()
    const roleMap = buildRoleMap(roles)
    return {
        roles: roles,
        users: listUsers(keyword, roleMap),
        collections: listManageableCollections(),
        note: '先创建角色，再在“用户授权”里把用户绑定到角色，最后切到下方“当前配置角色”为该角色逐表勾选 CRUD 权限。ManagePlatform 仍是业务管理员，不会变成 PocketBase 原生 _superusers。',
    }
}

module.exports = {
    getManagementContext,
    listRoles,
    saveRole,
    deleteRole,
    listUsers,
    updateUserRole,
    listManageableCollections,
    saveCollectionRules,
    syncManagePlatformFullAccess,
}
