package com.pdf.base.function

import android.content.Context
import android.net.Uri
import android.util.Log
import com.compdfkit.core.document.CPDFDocument
import com.compdfkit.core.document.CPDFDocument.PDFDocumentError
import com.pdf.base.impl.NormalOpenDocumentCallback
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.withContext

/**
 * @author: hubowen
 * @date: 2022/9/20
 * @description: LogicFunction 负责PDF的 打开逻辑，保存逻辑
 */

/**
 * 验证文档
 * onSuccess 返回一个正常的Document
 * onError 错误返回
 */

private suspend fun CPDFDocument.openDocument(uri: Uri?, absolutePath: String?, password: String? = ""): Flow<Pair<PDFDocumentError, CPDFDocument?>> {
    return flow {
        val result = try {
            val error =
                when {
                    uri != null -> if (password.isNullOrEmpty()) open(uri) else open(uri, password)
                    absolutePath.isNullOrEmpty().not() -> if (password.isNullOrEmpty()) open(absolutePath) else open(absolutePath, password)
                    else -> {
                        PDFDocumentError.PDFDocumentErrorUnknown
                    }
                }
            error to this@openDocument
        } catch (e: Exception) {
            e.printStackTrace()
            PDFDocumentError.PDFDocumentErrorUnknown to null
        }
        emit(result)
    }.flowOn(Dispatchers.IO)
}


/**
 * 转换至 Document对象，这里单独写出来，提供单独的document，用来做功能
 * onSuccess 返回一个正常的Document
 * NeedExit 错误返回
 */
suspend fun Context.openDocument(uri: Uri?, absolutePath: String?, password: String? = "", callback: NormalOpenDocumentCallback.() -> Unit) {
    val listener = NormalOpenDocumentCallback().also(callback)
    val document = CPDFDocument(this)
    document.openDocument(uri, absolutePath, password).collect {
        when (it.first) {
            PDFDocumentError.PDFDocumentErrorSuccess -> listener.success(cPdfDocument = it.second!!)
            PDFDocumentError.PDFDocumentErrorPassword -> {
                listener.isEncrypt(it.second!!)
            }
            else -> listener.fail(error = it.first)
        }
    }
}


/**
 * 重试打开文档，不会再调用回调中的isEncrypt()
 */
suspend fun CPDFDocument.retryOpenDocument(uri: Uri?, absolutePath: String?, password: String? = "", normalOpenDocumentCallback: NormalOpenDocumentCallback) {
    openDocument(uri, absolutePath, password).collect{ pair->
        when (pair.first) {
            PDFDocumentError.PDFDocumentErrorSuccess -> normalOpenDocumentCallback.success(cPdfDocument = pair.second!!)
            else -> normalOpenDocumentCallback.fail(error = pair.first)
        }
    }
}

/**
 * 文档是否已加密
 * @param uri 要检查的Uri文件
 * @param absolutePath 要检查的file 路径文件
 */
suspend fun Context.documentIsEncrypt(uri: Uri? = null, absolutePath: String? = ""): Boolean {
    val document = CPDFDocument(this)
    val result = document.openDocument(uri = uri, absolutePath = absolutePath, password = "")
        .firstOrNull()
    return result != null && result.first == PDFDocumentError.PDFDocumentErrorPassword
}




/**
 * 保存Document 这里有一个逻辑，先增量保存如果失败则进行全量保存。
 */
suspend fun CPDFDocument.onSaveDocument(isNeedClose: Boolean = false, onPre: (() -> Unit)? = null, onSuccess: ((Boolean) -> Unit)? = null, onComplete: (() -> Unit)? = null) {
    var isSaveSuccess: Boolean
    withContext(Dispatchers.Main) {
        onPre?.invoke()
        withContext(Dispatchers.IO) {
            runCatching {
                if (hasChanges()) {
                    //增量保存
                    isSaveSuccess = save()
                    //全量保存
                    if (!isSaveSuccess) isSaveSuccess = save(CPDFDocument.PDFDocumentSaveType.PDFDocumentSaveNoIncremental)
                }
            }.onFailure {
                Log.e("pdf_base", "save_failed")
                onSuccess?.invoke(false)
            }.onSuccess {
                Log.e("pdf_base", "save_success")
                onSuccess?.invoke(true)
            }
        }
        //关闭文档
        if (isNeedClose) close()
        onComplete?.invoke()
    }

}

/**
 * 另存PDF文件
 */

/**
 * 保存Flattened副本
 */