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

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

function normalizePublicBaseUrl() {
    const base = String(env.appBaseUrl || '').replace(/\/+$/, '')

    if (!base) return '/pb'
    if (base.toLowerCase().endsWith('/pb')) return base

    return base + '/pb'
}

function buildFileUrl(collectionName, recordId, filename, download) {
    if (!filename) return ''

    const base = normalizePublicBaseUrl()
    const url = base + '/api/files/' + encodeURIComponent(collectionName) + '/' + encodeURIComponent(recordId) + '/' + encodeURIComponent(filename)

    return download ? (url + '?download=1') : url
}

function normalizeDateValue(value) {
    const text = String(value || '').replace(/^\s+|\s+$/g, '')
    if (!text) return null

    if (/^\d{4}-\d{2}-\d{2}$/.test(text)) {
        return text + ' 00:00:00.000Z'
    }

    if (/^\d{4}-\d{2}-\d{2}\s/.test(text) || text.indexOf('T') !== -1) {
        return text
    }

    throw createAppError(400, '日期字段格式错误')
}

function extractDateOnly(value) {
    const text = String(value || '').replace(/^\s+|\s+$/g, '')
    const match = text.match(/^\d{4}-\d{2}-\d{2}/)
    return match ? match[0] : ''
}

function getTodayDateString() {
    const now = new Date()
    const year = now.getFullYear()
    const month = String(now.getMonth() + 1).padStart(2, '0')
    const day = String(now.getDate()).padStart(2, '0')
    return year + '-' + month + '-' + day
}

function calculateDocumentStatus(effectDate, expiryDate, fallbackStatus) {
    const start = extractDateOnly(effectDate)
    const end = extractDateOnly(expiryDate)
    const today = getTodayDateString()

    if (!start && !end) {
        return fallbackStatus === '过期' ? '过期' : '有效'
    }
    if (start && today < start) {
        return '过期'
    }
    if (end && today > end) {
        return '过期'
    }
    return '有效'
}

function ensureDocumentStatus(record) {
    const nextStatus = calculateDocumentStatus(
        record.get('document_effect_date'),
        record.get('document_expiry_date'),
        record.getString('document_status')
    )

    if (record.getString('document_status') !== nextStatus) {
        record.set('document_status', nextStatus)
        try {
            $app.save(record)
        } catch (_err) {}
    }

    return nextStatus
}

function normalizeNumberValue(value, fieldName) {
    if (value === '' || value === null || typeof value === 'undefined') {
        return 0
    }

    const num = Number(value)
    if (!Number.isFinite(num)) {
        throw createAppError(400, fieldName + ' 必须为数字')
    }

    return num
}

function normalizeOptionalNumberValue(value, fieldName) {
    if (value === '' || value === null || typeof value === 'undefined') {
        return null
    }

    return normalizeNumberValue(value, fieldName)
}

function parseAttachmentIdList(value) {
    if (Array.isArray(value)) {
        const result = []
        for (let i = 0; i < value.length; i += 1) {
            const current = String(value[i] || '').replace(/^\s+|\s+$/g, '')
            if (current && result.indexOf(current) === -1) {
                result.push(current)
            }
        }
        return result
    }

    const text = String(value || '').replace(/^\s+|\s+$/g, '')
    if (!text) return []

    const parts = text.split('|')
    const result = []
    for (let i = 0; i < parts.length; i += 1) {
        const current = String(parts[i] || '').replace(/^\s+|\s+$/g, '')
        if (current && result.indexOf(current) === -1) {
            result.push(current)
        }
    }

    return result
}

function serializeAttachmentIdList(value) {
    return parseAttachmentIdList(value).join('|')
}

function exportAttachmentRecord(record) {
    const storedFilename = record.getString('attachments_link')

    return {
        pb_id: record.id,
        attachments_id: record.getString('attachments_id'),
        attachments_link: storedFilename,
        attachments_url: buildFileUrl('tbl_attachments', record.id, storedFilename, false),
        attachments_download_url: buildFileUrl('tbl_attachments', record.id, storedFilename, true),
        attachments_filename: record.getString('attachments_filename'),
        attachments_filetype: record.getString('attachments_filetype'),
        attachments_size: record.get('attachments_size'),
        attachments_owner: record.getString('attachments_owner'),
        attachments_md5: record.getString('attachments_md5'),
        attachments_ocr: record.getString('attachments_ocr'),
        attachments_status: record.getString('attachments_status'),
        attachments_remark: record.getString('attachments_remark'),
        created: String(record.created || ''),
        updated: String(record.updated || ''),
    }
}

function findAttachmentRecordByAttachmentId(attachmentId) {
    if (!attachmentId) return null

    const records = $app.findRecordsByFilter('tbl_attachments', 'attachments_id = {:attachmentsId}', '', 1, 0, {
        attachmentsId: attachmentId,
    })

    return records.length ? records[0] : null
}

function fetchAllRecordsByFilter(collectionName, filter, sort, params) {
    const batchSize = 200
    const result = []
    let offset = 0

    while (true) {
        const batch = $app.findRecordsByFilter(
            collectionName,
            filter || '',
            sort || '',
            batchSize,
            offset,
            params || {}
        )

        if (!batch.length) {
            break
        }

        for (let i = 0; i < batch.length; i += 1) {
            result.push(batch[i])
        }

        if (batch.length < batchSize) {
            break
        }

        offset += batch.length
    }

    return result
}

function resolveAttachmentList(value) {
    const ids = parseAttachmentIdList(value)
    const attachments = []
    const urls = []

    for (let i = 0; i < ids.length; i += 1) {
        const currentRecord = findAttachmentRecordByAttachmentId(ids[i])
        if (!currentRecord) {
            continue
        }

        const exported = exportAttachmentRecord(currentRecord)
        attachments.push(exported)
        urls.push(exported.attachments_url)
    }

    return {
        ids: ids,
        attachments: attachments,
        urls: urls,
    }
}

function exportDocumentRecord(record) {
    const documentStatus = ensureDocumentStatus(record)
    const imageAttachmentList = resolveAttachmentList(record.getString('document_image'))
    const videoAttachmentList = resolveAttachmentList(record.getString('document_video'))
    const fileAttachmentList = resolveAttachmentList(record.getString('document_file'))
    const firstImageAttachment = imageAttachmentList.attachments.length ? imageAttachmentList.attachments[0] : null
    const firstVideoAttachment = videoAttachmentList.attachments.length ? videoAttachmentList.attachments[0] : null
    const firstFileAttachment = fileAttachmentList.attachments.length ? fileAttachmentList.attachments[0] : null

    return {
        pb_id: record.id,
        document_id: record.getString('document_id'),
        document_create: String(record.get('document_create') || ''),
        document_effect_date: String(record.get('document_effect_date') || ''),
        document_expiry_date: String(record.get('document_expiry_date') || ''),
        document_type: record.getString('document_type'),
        document_title: record.getString('document_title'),
        document_subtitle: record.getString('document_subtitle'),
        document_summary: record.getString('document_summary'),
        document_content: record.getString('document_content'),
        document_image: imageAttachmentList.ids.join('|'),
        document_image_ids: imageAttachmentList.ids,
        document_image_urls: imageAttachmentList.urls,
        document_image_attachments: imageAttachmentList.attachments,
        document_image_url: firstImageAttachment ? firstImageAttachment.attachments_url : '',
        document_image_attachment: firstImageAttachment,
        document_video: videoAttachmentList.ids.join('|'),
        document_video_ids: videoAttachmentList.ids,
        document_video_urls: videoAttachmentList.urls,
        document_video_attachments: videoAttachmentList.attachments,
        document_video_url: firstVideoAttachment ? firstVideoAttachment.attachments_url : '',
        document_video_attachment: firstVideoAttachment,
        document_file: fileAttachmentList.ids.join('|'),
        document_file_ids: fileAttachmentList.ids,
        document_file_urls: fileAttachmentList.urls,
        document_file_attachments: fileAttachmentList.attachments,
        document_file_url: firstFileAttachment ? firstFileAttachment.attachments_url : '',
        document_file_attachment: firstFileAttachment,
        document_owner: record.getString('document_owner'),
        document_relation_model: record.getString('document_relation_model'),
        document_keywords: record.getString('document_keywords'),
        document_share_count: record.get('document_share_count'),
        document_download_count: record.get('document_download_count'),
        document_favorite_count: record.get('document_favorite_count'),
        document_status: documentStatus,
        document_embedding_status: record.getString('document_embedding_status'),
        document_embedding_error: record.getString('document_embedding_error'),
        document_embedding_lasttime: String(record.get('document_embedding_lasttime') || ''),
        document_vector_version: record.getString('document_vector_version'),
        document_product_categories: record.getString('document_product_categories'),
        document_application_scenarios: record.getString('document_application_scenarios'),
        document_hotel_type: record.getString('document_hotel_type'),
        document_remark: record.getString('document_remark'),
        created: String(record.created || ''),
        updated: String(record.updated || ''),
    }
}

function findDocumentRecordByDocumentId(documentId) {
    const records = $app.findRecordsByFilter('tbl_document', 'document_id = {:documentId}', '', 1, 0, {
        documentId: documentId,
    })

    return records.length ? records[0] : null
}

function exportHistoryRecord(record) {
    return {
        pb_id: record.id,
        doh_id: record.getString('doh_id'),
        doh_document_id: record.getString('doh_document_id'),
        doh_operation_type: record.getString('doh_operation_type'),
        doh_user_id: record.getString('doh_user_id'),
        doh_current_count: record.get('doh_current_count'),
        doh_remark: record.getString('doh_remark'),
        created: String(record.created || ''),
        updated: String(record.updated || ''),
    }
}

function extractErrorDetails(err, fallbackMessage) {
    return {
        statusCode: (err && err.statusCode) || (err && err.status) || 400,
        message: (err && err.message) || fallbackMessage || '操作失败',
        data: (err && err.data) || {},
    }
}

function runInTransactionSafely(actionName, transactionHandler) {
    let result = null
    let capturedFailure = null

    try {
        $app.runInTransaction(function (txApp) {
            try {
                result = transactionHandler(txApp)
            } catch (err) {
                capturedFailure = extractErrorDetails(err, actionName + '失败')
                throw new Error(capturedFailure.message)
            }
        })
    } catch (err) {
        if (capturedFailure) {
            throw createAppError(capturedFailure.statusCode, capturedFailure.message, capturedFailure.data)
        }
        throw err
    }

    return result
}

function createHistoryRecord(txApp, payload) {
    const collection = txApp.findCollectionByNameOrId('tbl_document_operation_history')
    const record = new Record(collection)

    record.set('doh_id', buildBusinessId('DOH'))
    record.set('doh_document_id', payload.documentId)
    record.set('doh_operation_type', payload.operationType)
    record.set('doh_user_id', payload.userOpenid || '')
    record.set('doh_current_count', normalizeNumberValue(payload.currentCount, 'doh_current_count'))
    record.set('doh_remark', payload.remark || '')

    txApp.save(record)
}

function ensureAttachmentIdsExist(value, fieldName) {
    const attachmentIds = parseAttachmentIdList(value)

    for (let i = 0; i < attachmentIds.length; i += 1) {
        const record = findAttachmentRecordByAttachmentId(attachmentIds[i])
        if (!record) {
            throw createAppError(400, fieldName + ' 中存在不存在的附件：' + attachmentIds[i])
        }
    }
}

function listAttachments(payload) {
    const allRecords = $app.findRecordsByFilter('tbl_attachments', '', '', 500, 0)
    const keyword = String(payload.keyword || '').toLowerCase()
    const status = String(payload.status || '')
    const result = []

    for (let i = 0; i < allRecords.length; i += 1) {
        const item = exportAttachmentRecord(allRecords[i])
        const matchedKeyword = !keyword
            || item.attachments_id.toLowerCase().indexOf(keyword) !== -1
            || item.attachments_filename.toLowerCase().indexOf(keyword) !== -1
        const matchedStatus = !status || item.attachments_status === status

        if (matchedKeyword && matchedStatus) {
            result.push(item)
        }
    }

    return result
}

function getAttachmentDetail(attachmentId) {
    const record = findAttachmentRecordByAttachmentId(attachmentId)
    if (!record) {
        throw createAppError(404, '未找到对应附件')
    }

    return exportAttachmentRecord(record)
}

function uploadAttachment(userOpenid, payload, file) {
    if (!file) {
        throw createAppError(400, 'attachments_link 为必填文件')
    }

    const collection = $app.findCollectionByNameOrId('tbl_attachments')
    const record = new Record(collection)

    record.set('attachments_id', buildBusinessId('ATT'))
    record.set('attachments_link', file)
    record.set('attachments_filename', payload.attachments_filename || '')
    record.set('attachments_filetype', payload.attachments_filetype || '')
    record.set('attachments_size', normalizeNumberValue(payload.attachments_size, 'attachments_size'))
    record.set('attachments_owner', userOpenid || '')
    record.set('attachments_md5', payload.attachments_md5 || '')
    record.set('attachments_ocr', payload.attachments_ocr || '')
    record.set('attachments_status', payload.attachments_status || 'active')
    record.set('attachments_remark', payload.attachments_remark || '')

    try {
        $app.save(record)
    } catch (err) {
        throw createAppError(400, '上传附件失败', {
            originalMessage: (err && err.message) || '未知错误',
            originalData: (err && err.data) || {},
        })
    }

    logger.info('附件上传成功', {
        attachments_id: record.getString('attachments_id'),
        attachments_owner: userOpenid || '',
    })

    return exportAttachmentRecord(record)
}

function deleteAttachment(attachmentId) {
    const record = findAttachmentRecordByAttachmentId(attachmentId)
    if (!record) {
        throw createAppError(404, '未找到待删除的附件')
    }

    const documentRecords = fetchAllRecordsByFilter('tbl_document', '', '')
    for (let i = 0; i < documentRecords.length; i += 1) {
        const current = documentRecords[i]
        const imageIds = parseAttachmentIdList(current.getString('document_image'))
        const videoIds = parseAttachmentIdList(current.getString('document_video'))

        const fileIds = parseAttachmentIdList(current.getString('document_file'))

        if (imageIds.indexOf(attachmentId) !== -1 || videoIds.indexOf(attachmentId) !== -1 || fileIds.indexOf(attachmentId) !== -1) {
            throw createAppError(400, '附件已被文档引用，无法删除')
        }
    }

    try {
        $app.delete(record)
    } catch (err) {
        throw createAppError(400, '删除附件失败', {
            originalMessage: (err && err.message) || '未知错误',
            originalData: (err && err.data) || {},
        })
    }

    logger.info('附件删除成功', {
        attachments_id: attachmentId,
    })

    return {
        attachments_id: attachmentId,
    }
}

function listDocuments(payload) {
    const allRecords = fetchAllRecordsByFilter('tbl_document', '', '')
    const titleKeyword = String(payload.title_keyword || '').toLowerCase().trim()
    const status = String(payload.status || '')
    const type = String(payload.document_type || '')
    const result = []

    for (let i = 0; i < allRecords.length; i += 1) {
        const item = exportDocumentRecord(allRecords[i])
        const matchedTitleKeyword = !titleKeyword
            || item.document_title.toLowerCase().indexOf(titleKeyword) !== -1
        const matchedStatus = !status || item.document_status === status
        const matchedType = !type || String(item.document_type || '')
            .split('|')
            .map(function (token) { return String(token || '').trim() })
            .some(function (token) {
                if (!token) {
                    return false
                }
                if (token === type) {
                    return true
                }
                return token.indexOf(type + '@') === 0
            })

        if (matchedTitleKeyword && matchedStatus && matchedType) {
            result.push(item)
        }
    }

    result.sort(function (a, b) {
        return String(b.updated || '').localeCompare(String(a.updated || ''))
    })

    return result
}

function getDocumentDetail(documentId) {
    const record = findDocumentRecordByDocumentId(documentId)
    if (!record) {
        throw createAppError(404, '未找到对应文档')
    }

    return exportDocumentRecord(record)
}

function createDocument(userOpenid, payload) {
    ensureAttachmentIdsExist(payload.document_image, 'document_image')
    ensureAttachmentIdsExist(payload.document_video, 'document_video')
    ensureAttachmentIdsExist(payload.document_file, 'document_file')

    const targetDocumentId = payload.document_id || buildBusinessId('DOC')
    const duplicated = findDocumentRecordByDocumentId(targetDocumentId)
    if (duplicated) {
        throw createAppError(400, 'document_id 已存在')
    }

    return runInTransactionSafely('创建文档', function (txApp) {
        const collection = txApp.findCollectionByNameOrId('tbl_document')
        const record = new Record(collection)
        const effectDateValue = normalizeDateValue(payload.document_effect_date)
        const expiryDateValue = normalizeDateValue(payload.document_expiry_date)
        const documentStatus = calculateDocumentStatus(effectDateValue, expiryDateValue, payload.document_status)

        record.set('document_id', targetDocumentId)
        record.set('document_effect_date', effectDateValue)
        record.set('document_expiry_date', expiryDateValue)
        record.set('document_type', payload.document_type || '')
        record.set('document_title', payload.document_title || '')
        record.set('document_subtitle', payload.document_subtitle || '')
        record.set('document_summary', payload.document_summary || '')
        record.set('document_content', payload.document_content || '')
        record.set('document_image', serializeAttachmentIdList(payload.document_image))
        record.set('document_video', serializeAttachmentIdList(payload.document_video))
        record.set('document_file', serializeAttachmentIdList(payload.document_file))
        record.set('document_owner', userOpenid || '')
        record.set('document_relation_model', payload.document_relation_model || '')
        record.set('document_keywords', payload.document_keywords || '')
        record.set('document_share_count', normalizeNumberValue(payload.document_share_count, 'document_share_count'))
        record.set('document_download_count', normalizeNumberValue(payload.document_download_count, 'document_download_count'))
        record.set('document_favorite_count', normalizeNumberValue(payload.document_favorite_count, 'document_favorite_count'))
        record.set('document_status', documentStatus)
        record.set('document_embedding_status', payload.document_embedding_status || '')
        record.set('document_embedding_error', payload.document_embedding_error || '')
        record.set('document_embedding_lasttime', normalizeDateValue(payload.document_embedding_lasttime))
        record.set('document_vector_version', payload.document_vector_version || '')
        record.set('document_product_categories', payload.document_product_categories || '')
        record.set('document_application_scenarios', payload.document_application_scenarios || '')
        record.set('document_hotel_type', payload.document_hotel_type || '')
        record.set('document_remark', payload.document_remark || '')

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

        createHistoryRecord(txApp, {
            documentId: record.getString('document_id'),
            operationType: 'create',
            userOpenid: userOpenid,
            currentCount: 1,
            remark: '文档创建',
        })

        return exportDocumentRecord(record)
    })
}

function updateDocument(userOpenid, payload) {
    const record = findDocumentRecordByDocumentId(payload.document_id)
    if (!record) {
        throw createAppError(404, '未找到待修改的文档')
    }

    ensureAttachmentIdsExist(payload.document_image, 'document_image')
    ensureAttachmentIdsExist(payload.document_video, 'document_video')
    ensureAttachmentIdsExist(payload.document_file, 'document_file')

    return runInTransactionSafely('更新文档', function (txApp) {
        const target = txApp.findRecordById('tbl_document', record.id)
        const effectDateValue = normalizeDateValue(payload.document_effect_date)
        const expiryDateValue = normalizeDateValue(payload.document_expiry_date)
        const documentStatus = calculateDocumentStatus(effectDateValue, expiryDateValue, payload.document_status)

        target.set('document_effect_date', effectDateValue)
        target.set('document_expiry_date', expiryDateValue)
        target.set('document_type', payload.document_type || '')
        target.set('document_title', payload.document_title || '')
        target.set('document_subtitle', payload.document_subtitle || '')
        target.set('document_summary', payload.document_summary || '')
        target.set('document_content', payload.document_content || '')
        target.set('document_image', serializeAttachmentIdList(payload.document_image))
        target.set('document_video', serializeAttachmentIdList(payload.document_video))
        target.set('document_file', serializeAttachmentIdList(payload.document_file))
        target.set('document_relation_model', payload.document_relation_model || '')
        target.set('document_keywords', payload.document_keywords || '')
        target.set('document_share_count', normalizeNumberValue(payload.document_share_count, 'document_share_count'))
        target.set('document_download_count', normalizeNumberValue(payload.document_download_count, 'document_download_count'))
        target.set('document_favorite_count', normalizeNumberValue(payload.document_favorite_count, 'document_favorite_count'))
        target.set('document_status', documentStatus)
        target.set('document_embedding_status', payload.document_embedding_status || '')
        target.set('document_embedding_error', payload.document_embedding_error || '')
        target.set('document_embedding_lasttime', normalizeDateValue(payload.document_embedding_lasttime))
        target.set('document_vector_version', payload.document_vector_version || '')
        target.set('document_product_categories', payload.document_product_categories || '')
        target.set('document_application_scenarios', payload.document_application_scenarios || '')
        target.set('document_hotel_type', payload.document_hotel_type || '')
        target.set('document_remark', payload.document_remark || '')

        try {
            txApp.save(target)
        } catch (err) {
            throw createAppError(400, '保存文档失败', {
                originalMessage: (err && err.message) || '未知错误',
                originalData: (err && err.data) || {},
            })
        }

        createHistoryRecord(txApp, {
            documentId: target.getString('document_id'),
            operationType: 'update',
            userOpenid: userOpenid,
            currentCount: 1,
            remark: '文档更新',
        })

        return exportDocumentRecord(target)
    })
}

function deleteDocument(userOpenid, documentId) {
    const record = findDocumentRecordByDocumentId(documentId)
    if (!record) {
        throw createAppError(404, '未找到待删除的文档')
    }

    return runInTransactionSafely('删除文档', function (txApp) {
        createHistoryRecord(txApp, {
            documentId: documentId,
            operationType: 'delete',
            userOpenid: userOpenid,
            currentCount: 1,
            remark: '文档删除',
        })

        const target = txApp.findRecordById('tbl_document', record.id)
        txApp.delete(target)

        logger.info('文档删除成功', {
            document_id: documentId,
        })

        return {
            document_id: documentId,
        }
    })
}

function listDocumentHistories(payload) {
    const allRecords = payload.document_id
        ? $app.findRecordsByFilter('tbl_document_operation_history', 'doh_document_id = {:documentId}', '', 500, 0, {
            documentId: payload.document_id,
        })
        : $app.findRecordsByFilter('tbl_document_operation_history', '', '', 500, 0)

    const result = []
    for (let i = 0; i < allRecords.length; i += 1) {
        result.push(exportHistoryRecord(allRecords[i]))
    }

    result.sort(function (a, b) {
        return String(b.created || '').localeCompare(String(a.created || ''))
    })

    return result
}

module.exports = {
    listAttachments,
    getAttachmentDetail,
    uploadAttachment,
    deleteAttachment,
    listDocuments,
    getDocumentDetail,
    createDocument,
    updateDocument,
    deleteDocument,
    listDocumentHistories,
}
