package com.kdanmobile.reader

import android.arch.lifecycle.LiveData
import android.arch.lifecycle.MutableLiveData
import android.arch.lifecycle.ViewModel
import android.content.Context
import android.graphics.Color
import android.graphics.Bitmap
import android.graphics.RectF
import android.net.Uri
import com.kdanmobile.kmpdfkit.annotation.Annotation
import com.kdanmobile.kmpdfkit.annotation.bean.*
import com.kdanmobile.kmpdfkit.contextmenu.KMPDFMenuItem
import com.kdanmobile.kmpdfkit.contextmenu.MenuItemCallback
import com.kdanmobile.kmpdfkit.globaldata.AnnotConfig
import com.kdanmobile.kmpdfkit.globaldata.Config
import com.kdanmobile.kmpdfkit.globaldata.KMPDFAnnotEditMode
import com.kdanmobile.kmpdfkit.manager.KMPDFFactory
import com.kdanmobile.kmpdfkit.manager.controller.KMPDFDocumentController
import com.kdanmobile.kmpdfkit.pdfcommon.KMPDFReaderView
import com.kdanmobile.reader.annotationattribute.AnnotationAttribute
import com.kdanmobile.reader.annotationattribute.InkAttribute
import com.kdanmobile.kmpdfkit.pdfcommon.*
import com.kdanmobile.reader.annotationattribute.Brush
import com.kdanmobile.kmpdfkit.manager.controller.*
import com.kdanmobile.kmpdfkit.manager.listener.KMPDFAddAnnotCallback
import com.kdanmobile.kmpdfkit.manager.listener.KMPDFAnnotEditModeChangeListener
import com.kdanmobile.reader.screen.contextmenu.TextBoxContextMenuActionListener
import com.kdanmobile.reader.screen.data.ShapeAttribute
import com.kdanmobile.reader.screen.data.SignatureAttribute
import com.kdanmobile.reader.screen.data.StampAttribute
import com.kdanmobile.reader.screen.data.TextBoxAttribute
import com.kdanmobile.reader.screen.handler.*

class ReaderViewModel(private val pdfSdkLicense: String, private val pdfSdkRsaMsg: String) : ViewModel() {

    enum class ViewDirection(val mode: Config.PDFViewMode) {
        VerticalSinglePageContinues(Config.PDFViewMode.VERTICAL_SINGLE_PAGE_CONTINUES),
        VerticalSinglePage(Config.PDFViewMode.VERTICAL_SINGLE_PAGE),
        HorizontalSinglePage(Config.PDFViewMode.HORIZONTAL_SINGLE_PAGE)
    }

    enum class AnnotationMode {
        None,
        Highlight,
        Strike,
        Underline,
        Ink,
    }

    companion object {
        val DEFAULT_HIGHLIGHT_ATTR = AnnotationAttribute(Color.parseColor("#ffdc1b"), 127)
        val DEFAULT_STRIKE_ATTR = AnnotationAttribute(Color.parseColor("#dd0202"), 255)
        val DEFAULT_UNDERLINE_ATTR = AnnotationAttribute(Color.parseColor("#dd0202"), 255)
        val DEFAULT_INK_ATTR = InkAttribute(Color.parseColor("#dd0202"), 255, 1f, Brush.Fountain)
    }

    var viewDirection = ViewDirection.VerticalSinglePageContinues
        set(value) {
            field = value
            updateViewDirection()
        }
    var isCrop = false
        set(value) {
            field = value
            updateCrop()
        }
    val highLightAttributeLiveData = MutableLiveData<AnnotationAttribute>().apply { value = DEFAULT_HIGHLIGHT_ATTR }
    val strikeAttributeLiveData = MutableLiveData<AnnotationAttribute>().apply { value = DEFAULT_STRIKE_ATTR }
    var underLineAttributeLiveData = MutableLiveData<AnnotationAttribute>().apply { value = DEFAULT_UNDERLINE_ATTR }
    var inkAttributeLiveData = MutableLiveData<InkAttribute>().apply { value = DEFAULT_INK_ATTR }

    private var isVerified = false

    private var kmpdfFactory: KMPDFFactory? = null
    private var kmpdfDocumentController: KMPDFDocumentController? = null
    val isOpenedFileLiveData = MutableLiveData<Boolean>().apply { value = false }
    val fileNameLiveData = MutableLiveData<String>()
    val annotationModeLiveData = MutableLiveData<AnnotationMode>().apply { value = AnnotationMode.None }
    val annotationEitModeLiveData = MutableLiveData<KMPDFAnnotEditMode.Mode>().apply { value = KMPDFAnnotEditMode.Mode.NULL }
    var isCopyModeLiveData = MutableLiveData<Boolean>().apply { value = false }

    val pageIndexLiveData: LiveData<Int>
        get() = mPageIndexLiveData
    val isPageInBookmarksLiveData: LiveData<Boolean>
        get() = mIsPageInBookmarksLiveData

    private val mPageIndexLiveData = MutableLiveData<Int>().apply { value = 0 }
    private val mIsPageInBookmarksLiveData = MutableLiveData<Boolean>().apply { value = false }

    enum class LeftToolbarType {
        NONE, THUMBNAIL, BOOKMARK, OUTLINE, SEARCH
    }

    val leftToolbarTypeLiveData: LiveData<LeftToolbarType>
        get() = mLeftToolbarTypeLiveData
    private val mLeftToolbarTypeLiveData = MutableLiveData<LeftToolbarType>().apply { value = LeftToolbarType.NONE }

    val isLeftToolbarOpenLiveData: LiveData<Boolean>
        get() = mIsLeftToolbarOpenLiveData
    private val mIsLeftToolbarOpenLiveData = MutableLiveData<Boolean>().apply { value = false }

    fun setLeftToolbarType(leftToolbarType: LeftToolbarType) {
        mLeftToolbarTypeLiveData.postValue(leftToolbarType)
    }

    fun setIsLeftToolbarOpen(open: Boolean) {
        mIsLeftToolbarOpenLiveData.postValue(open)
    }

    @JvmOverloads
    fun openPdfFile(context: Context, uri: Uri, type: String? = null): Boolean {
        if (!isVerified) {
            if (!verifyLicense(context)) {
                return false
            }
        }
        return openPdfFIleImp(context, uri, type).apply{
            isOpenedFileLiveData.postValue(this)
        }
    }

    private fun openPdfFIleImp(context: Context, uri: Uri, type: String?): Boolean {
        val factory = KMPDFFactory.open(context, uri, type) ?: return false
        kmpdfFactory = factory
        kmpdfFactory?.also {
            fileNameLiveData.postValue(it.fileName)
            return when {
                it.needPassWord() -> {
                    false
                }
                it.init() -> {
                    true
                }
                else -> {
                    false
                }
            }
        }
        return false
    }

    fun copySelection(): Boolean {
        return kmpdfDocumentController?.copySelection() ?: false
    }

    fun onClickCopyBtn() {
        if (annotationModeLiveData.value != AnnotationMode.None) stopAnnotationMode()
        if (isCopyModeLiveData.value == true) {
            stopCopyTextMode()
        } else {
            startCopyTextMode()
        }
    }

    fun onClickHighlightBtn() {
        if (isCopyModeLiveData.value == true) stopCopyTextMode()
        if (annotationModeLiveData.value == AnnotationMode.Highlight) {
            stopAnnotationMode()
        } else {
            startHighLightEditMode()
        }
    }

    fun onLongClickHighlightBtn() {
        if (isCopyModeLiveData.value == true) stopCopyTextMode()
        startHighLightEditMode()
    }

    fun onClickStrikeBtn() {
        if (isCopyModeLiveData.value == true) stopCopyTextMode()
        if (annotationModeLiveData.value == AnnotationMode.Strike) {
            stopAnnotationMode()
        } else {
            startStrikeOutEditMode()
        }
    }

    fun onLongClickStrikeBtn() {
        if (isCopyModeLiveData.value == true) stopCopyTextMode()
        startStrikeOutEditMode()
    }

    fun onClickUnderlineBtn() {
        if (isCopyModeLiveData.value == true) stopCopyTextMode()
        if (annotationModeLiveData.value == AnnotationMode.Underline) {
            stopAnnotationMode()
        } else {
            startUnderLineEditMode()
        }
    }

    fun onLongClickUnderlineBtn() {
        if (isCopyModeLiveData.value == true) stopCopyTextMode()
        startUnderLineEditMode()
    }

    fun onClickInkBtn() {
        if (isCopyModeLiveData.value == true) stopCopyTextMode()
        if (annotationModeLiveData.value == AnnotationMode.Ink) {
            stopAnnotationMode()
        } else {
            startInkEditMode()
        }
    }

    fun onLongClickInkBtn() {
        if (isCopyModeLiveData.value == true) stopCopyTextMode()
        startInkEditMode()
    }

    private fun startCopyTextMode() {
        kmpdfDocumentController?.startCopyText()
        isCopyModeLiveData.postValue(true)
    }

    private fun stopCopyTextMode() {
        kmpdfDocumentController?.stopCopyText()
        isCopyModeLiveData.postValue(false)
    }

    fun setHighLightAttributes(annotationAttribute: AnnotationAttribute) {
        highLightAttributeLiveData.postValue(annotationAttribute)
        kmpdfFactory?.setAnnotationAttribute(KMPDFHighlightAnnotationBean("", annotationAttribute.color, annotationAttribute.alpha))
        kmpdfFactory?.annotConfig?.apply {
            markerPenColor_hightlight = annotationAttribute.color
            markerPenAlpha_hightlight = annotationAttribute.alpha
        }
    }

    private fun startHighLightEditMode() {
        kmpdfFactory?.setAnnotationEditMode(KMPDFAnnotationBean.AnnotationType.HIGH_LIGHT)
        annotationModeLiveData.postValue(AnnotationMode.Highlight)
    }

    fun setStrikeOutAttributes(annotationAttribute: AnnotationAttribute) {
        strikeAttributeLiveData.postValue(annotationAttribute)
        kmpdfFactory?.setAnnotationAttribute(KMPDFStrikeoutAnnotationBean("",annotationAttribute.color, annotationAttribute.alpha))
        kmpdfFactory?.annotConfig?.apply {
            markerPenColor_strikeout = annotationAttribute.color
            markerPenAlpha_strikeout = annotationAttribute.alpha
        }
    }

    private fun startStrikeOutEditMode() {
        kmpdfFactory?.setAnnotationEditMode(KMPDFAnnotationBean.AnnotationType.STRIKE_OUT)
        annotationModeLiveData.postValue(AnnotationMode.Strike)
    }

    fun setUnderLineAttributes(annotationAttribute: AnnotationAttribute) {
        underLineAttributeLiveData.postValue(annotationAttribute)
        kmpdfFactory?.setAnnotationAttribute(KMPDFUnderlineAnnotationBean("", annotationAttribute.color, annotationAttribute.alpha))
        kmpdfFactory?.annotConfig?.apply {
            markerPenColor_underline = annotationAttribute.color
            markerPenAlpha_underline = annotationAttribute.alpha
        }
    }

    private fun startUnderLineEditMode() {
        kmpdfFactory?.setAnnotationEditMode(KMPDFAnnotationBean.AnnotationType.UNDER_LINE)
        annotationModeLiveData.postValue(AnnotationMode.Underline)
    }

    fun setInkAttributes(inkAttribute: InkAttribute) {
        inkAttributeLiveData.postValue(inkAttribute)
        kmpdfFactory?.apply {
            setAnnotationAttribute(KMPDFInkAnnotationBean("", inkAttribute.color, inkAttribute.width, inkAttribute.alpha))
            annotConfig?.apply {
                markerPenColor_ink = inkAttribute.color
                markerPenAlpha_ink = inkAttribute.alpha
                markerPenSize_ink = inkAttribute.width
            }
        }
    }

    private fun startInkEditMode() {
        kmpdfFactory?.setAnnotationEditMode(KMPDFAnnotationBean.AnnotationType.INK)
        annotationModeLiveData.postValue(AnnotationMode.Ink)
    }

    private fun stopAnnotationMode() {
        kmpdfFactory?.setAnnotationEditMode(KMPDFAnnotationBean.AnnotationType.NULL)
        annotationModeLiveData.postValue(AnnotationMode.None)
    }

    fun setReaderView(readerView: KMPDFReaderView) {
        val isFirst = kmpdfFactory?.readerView == null
        kmpdfFactory?.readerView = readerView
        kmpdfDocumentController = kmpdfFactory?.getController(KMPDFFactory.ControllerType.DOCUMENT) as KMPDFDocumentController
        updateViewDirection()

        kmpdfFactory?.kmpdfAddAnnotCallback = object : KMPDFAddAnnotCallback {

            override fun onSaveAnnotFinished(type: Annotation.Type, result: Boolean, message: String) {
                println("KMPDFAddAnnotCallback::onSaveAnnotFinished")
            }

            override fun onAttachAnnotWidgetFinished(type: Annotation.Type) {
                println("KMPDFAddAnnotCallback::onAttachAnnotWidgetFinished")
                val mode = when (type) {
                    Annotation.Type.FREETEXT -> KMPDFAnnotEditMode.Mode.FREETEXT_MODIFY
                    Annotation.Type.STAMP -> KMPDFAnnotEditMode.Mode.STAMP_MODIFY
                    Annotation.Type.CIRCLE, Annotation.Type.SQUARE, Annotation.Type.LINE -> KMPDFAnnotEditMode.Mode.SHAPE_MODIFY
                    else -> KMPDFAnnotEditMode.Mode.NULL
                }
                if (mode != KMPDFAnnotEditMode.Mode.NULL) {
                    kmpdfFactory?.kmpdfAnnotEditMode?.pdfAnnotEditMode = mode
                }
            }
        }

        kmpdfFactory?.kmpdfAnnotEditModeChangeListener = KMPDFAnnotEditModeChangeListener {
            annotationEitModeLiveData.postValue(it)
        }

        setLongPressContextMenuActions()

        if (!isFirst) {
            restoreStateBeforeDestroy()
        }
    }

    private fun setLongPressContextMenuActions() {
        val item = KMPDFMenuItem()
        item.annotType = KMPDFMenuItem.AnnotType.LONG_PRESS
        item.menu_resId = R.menu.context_menu_longpress
        item.menuCallbacks.add(MenuItemCallback { view, annotType ->
            (kmpdfFactory?.getController(KMPDFFactory.ControllerType.LONGCLICK) as KMPDFLongPressCreateAnnotController).longPress_Paste()
            annotationEitModeLiveData.postValue(KMPDFAnnotEditMode.Mode.FREETEXT_MODIFY)

            return@MenuItemCallback true
        })
        kmpdfFactory?.setAnnotationContextMenu(item)
    }

    fun setTextBoxContextMenuActions(listener: TextBoxContextMenuActionListener) {
        val item = KMPDFMenuItem()
        item.annotType = KMPDFMenuItem.AnnotType.FREETEXT
        item.menu_resId = R.menu.context_menu_textbox
        item.menuCallbacks.add(MenuItemCallback { view, annotType ->
            return@MenuItemCallback listener.onDelete()
        })
        item.menuCallbacks.add(MenuItemCallback { view, annotType ->
            return@MenuItemCallback listener.onEditStyle()
        })
        item.menuCallbacks.add(MenuItemCallback { view, annotType ->
            return@MenuItemCallback listener.onEditText()
        })
        item.menuCallbacks.add(MenuItemCallback { view, annotType ->
            return@MenuItemCallback listener.onCopy()
        })
        kmpdfFactory?.setAnnotationContextMenu(item)
    }

    private fun restoreStateBeforeDestroy() {
        if (isCopyModeLiveData.value == true) {
            startCopyTextMode()
        } else {
            val annotationEditMode = when (annotationModeLiveData.value) {
                AnnotationMode.None, null -> KMPDFAnnotationBean.AnnotationType.NULL
                AnnotationMode.Highlight -> KMPDFAnnotationBean.AnnotationType.HIGH_LIGHT
                AnnotationMode.Strike -> KMPDFAnnotationBean.AnnotationType.STRIKE_OUT
                AnnotationMode.Underline -> KMPDFAnnotationBean.AnnotationType.UNDER_LINE
                AnnotationMode.Ink -> KMPDFAnnotationBean.AnnotationType.INK
            }
            kmpdfFactory?.setAnnotationEditMode(annotationEditMode)
            kmpdfFactory?.kmpdfAnnotEditMode?.pdfAnnotEditMode = KMPDFAnnotEditMode.Mode.NULL
            annotationEitModeLiveData.postValue(KMPDFAnnotEditMode.Mode.NULL)
        }
    }

    fun saveModifyingAnnotationBeforeDestroy() {
        kmpdfFactory?.setAnnotationEditMode(KMPDFAnnotationBean.AnnotationType.NULL)
    }

    fun clearSelection() {
        kmpdfFactory?.setAnnotationEditMode(KMPDFAnnotationBean.AnnotationType.NULL)
        kmpdfFactory?.kmpdfAnnotEditMode?.pdfAnnotEditMode = KMPDFAnnotEditMode.Mode.NULL
        annotationEitModeLiveData.postValue(KMPDFAnnotEditMode.Mode.NULL)
    }

    fun deleteSelectedTextBox() {
        (kmpdfFactory?.getController(KMPDFFactory.ControllerType.FREETEXT) as KMPDFFreeTextController).deleteFreeTextAnnotView()
    }

    fun editSelectedTextBoxStyle() {
        (kmpdfFactory?.getController(KMPDFFactory.ControllerType.FREETEXT) as KMPDFFreeTextController).setCurrentFreeTextViewEditMode(0)
    }

    fun editSelectedTextBoxText() {
        (kmpdfFactory?.getController(KMPDFFactory.ControllerType.FREETEXT) as KMPDFFreeTextController).setCurrentFreeTextViewEditMode(1)
    }

    fun copySelectedTextBox() {
        (kmpdfFactory?.getController(KMPDFFactory.ControllerType.FREETEXT) as KMPDFFreeTextController).copyFreeTextContent()
    }

    fun setPageIndex(pageIndex: Int){
        mPageIndexLiveData.value = pageIndex
    }

    fun addBookmark(title: String) {
        pageIndexLiveData.value?.let {
            kmpdfDocumentController?.addBookmark(title, it)
            setBookmarkDisplay(it)
        }
    }

    fun deleteBookmark() {
        pageIndexLiveData.value?.let {
            kmpdfDocumentController?.deleteBookmarks(it)
            setBookmarkDisplay(it)
        }
    }

    fun setBookmarkDisplay(pageIndex: Int) {
        kmpdfDocumentController?.let {
            var isPageInBookmarks = false
            it.bookmarks?.let {
                for (bookmark in it) {
                    if (bookmark.pageNum == pageIndex) {
                        isPageInBookmarks = true
                        break
                    }
                }
            }
            mIsPageInBookmarksLiveData.value = isPageInBookmarks
        }
    }

    private fun verifyLicense(context: Context): Boolean {
        val errorCode = KMPDFFactory.verifyLicense(context, pdfSdkLicense, pdfSdkRsaMsg)
        return errorCode == 0
    }

    private fun updateViewDirection() {
        kmpdfDocumentController?.pdfViewMode = viewDirection.mode
        kmpdfDocumentController?.refresh(false)
    }

    private fun updateCrop() {
        kmpdfDocumentController?.apply {
            cropMode = isCrop
            refresh(false)
        }
    }

    fun setTextBoxAttribute(attr: TextBoxAttribute, modify: Boolean = false) {

        val kmpdfFreetextAnnotationBean = KMPDFFreetextAnnotationBean("", attr.textColor, attr.textSize, 255, "Courier", attr.isBold, attr.isItalic)
        kmpdfFactory?.setAnnotationAttribute(kmpdfFreetextAnnotationBean)
        if (!modify) {
            kmpdfFactory?.setAnnotationEditMode(KMPDFAnnotationBean.AnnotationType.FREETEXT)
        }
    }

    fun setSignatureAttribute(attr: SignatureAttribute) {

        val kmpdfSignatureAnnotationBean = KMPDFSignatureAnnotationBean("", attr.path, KMPDFSignatureController.OnSignImageCreateListener {
            println("onSignImageCreated")
        })
        kmpdfFactory?.setAnnotationAttribute(kmpdfSignatureAnnotationBean)
        kmpdfFactory?.setAnnotationEditMode(KMPDFAnnotationBean.AnnotationType.SIGNATURE)
    }

    fun setStampAttribute(attr: StampAttribute) {

        val kmpdfStampAnnotationBean = when (attr.isStandardStamp()) {
            true -> KMPDFStampAnnotationBean("", KMPDFStampAnnotationBean.StampType.STANDARD, KMPDFStampAnnotationBean.StandardStamp(attr.resId))
            false -> KMPDFStampAnnotationBean("", KMPDFStampAnnotationBean.StampType.TEXT, KMPDFStampAnnotationBean.TextStamp(attr.rect, attr.config))
        }
        kmpdfFactory?.setAnnotationAttribute(kmpdfStampAnnotationBean)
        kmpdfFactory?.setAnnotationEditMode(KMPDFAnnotationBean.AnnotationType.STAMP)
    }

    fun setShapeAttribute(attr: ShapeAttribute) {

        val kmpdfShapeAnnotationBean = when (attr.shapeType) {
            AnnotConfig.ShapeAnnotationType.LINE -> KMPDFLineAnnotationBean("", attr.lineColor, attr.lineWidth, attr.lineAlpha)
            AnnotConfig.ShapeAnnotationType.ARROW -> KMPDFArrowAnnotationBean("", attr.lineColor, attr.lineWidth, attr.lineAlpha)
            AnnotConfig.ShapeAnnotationType.CIRCLE -> KMPDFCircleAnnotationBean("", attr.lineColor, attr.lineWidth, attr.lineAlpha, attr.fillColor, attr.fillAlpha)
            AnnotConfig.ShapeAnnotationType.SQUARE -> KMPDFSquareAnnotationBean("", attr.lineColor, attr.lineWidth, attr.lineAlpha, attr.fillColor, attr.fillAlpha)
        }
        kmpdfFactory?.setAnnotationAttribute(kmpdfShapeAnnotationBean)
        kmpdfFactory?.setAnnotationEditMode(kmpdfShapeAnnotationBean.type)
    }

    val pdfInfoHandler = object : PdfInfoHandler {
        override fun getOpenPdfFilename(): String {
            return kmpdfFactory?.fileName ?: ""
        }

        override fun getPdfPageCount(): Int {
            return kmpdfDocumentController?.getDocumentPageCount(false) ?: 0
        }

        override fun getCurrentPage(): Int {
            return kmpdfDocumentController?.currentPageNum ?: 0
        }

        override fun setCurrentPage(page: Int): Boolean {
            return kmpdfDocumentController?.gotoPage(page) ?: false
        }

        override fun textLines(page: Int): Array<Array<TextWord>> {
            return kmpdfDocumentController?.textLines(page) ?: arrayOf()
        }
    }

    val thumbnailHandler = object : ThumbnailHandler {
        override fun getPdfBitmap(position: Int, picWidth: Int, mode: Int, isDrawAnnot: Boolean): Bitmap {
            return kmpdfDocumentController?.covertPDFToBitmap(position, picWidth, mode, isDrawAnnot) ?: Bitmap.createBitmap(0, 0, Bitmap.Config.ARGB_4444)
        }
    }

    val bookmarkHandler = object : BookmarkHandler {
        override fun getBookmarks(): Array<Bookmark> {
            return kmpdfDocumentController?.bookmarks ?: arrayOf()
        }
    }

    val outlineHandler = object : OutlineHandler {
        override fun getOutline(): Array<OutlineItem> {
            return kmpdfDocumentController?.outline ?: arrayOf()
        }
    }

    val searchHandler = object : SearchHandler {
        override fun searchPage(page: Int, keyword: String): Array<RectF> {
            return kmpdfDocumentController?.searchPage(page, keyword) ?: arrayOf()
        }

        override fun cleanPreviousSearchResults(keyword: String): Boolean {
            return kmpdfDocumentController?.cleanPreviousSearchResults(keyword) ?: false
        }

        override fun setSearchResult(page: Int, keyword: String, rectArray: Array<RectF>): Boolean {
            return kmpdfDocumentController?.setSearchResult(keyword, page, rectArray) ?: false
        }

        override fun stopSearchKeyWord(): Boolean {
            return kmpdfDocumentController?.stopSearchKeyWord() ?: false
        }
    }
}