package com.kdanmobile.reader

import android.annotation.SuppressLint
import android.arch.lifecycle.Observer
import android.arch.lifecycle.ViewModelProviders
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.constraint.ConstraintLayout
import android.support.constraint.ConstraintSet
import android.support.v4.content.ContextCompat
import android.support.v7.app.AlertDialog
import android.view.Menu
import android.view.MenuItem
import android.util.DisplayMetrics
import android.view.MotionEvent
import android.view.View
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.TextView
import com.kdanmobile.kmpdfkit.pdfcommon.KMPDFReaderView
import com.kdanmobile.reader.Utils.applyConstraintSet
import com.kdanmobile.reader.utils.AnimationUtil
import com.kdanmobile.reader.utils.DensityUtil
import com.kdanmobile.reader.screen.ViewerSettingActivity
import com.kdanmobile.reader.screen.view.*
import com.kdanmobile.reader.screen.view.edit.ShapeTabView
import com.kdanmobile.reader.screen.view.edit.StampTabView
import com.kdanmobile.reader.screen.view.edit.TextBoxTabView
import kotlinx.android.synthetic.main.activity_reader.*
import kotlin.Exception

abstract class ReaderActivity : AppCompatActivity() {

    abstract fun onClickShare()
    abstract fun onClickTextReflow()
    abstract fun onClickFileInfo()
    abstract fun onClickPrint()
    abstract fun onClickUserGuide()

    companion object {
        const val KEY_FILE_ABSOLUTE = "file_absolutepath"
    }

    private lateinit var viewModel: ReaderViewModel

    // For hide/show toolbars
    private var isHideToolbar = false
    private lateinit var originConstraintSet: ConstraintSet

    private var menuItemBookmark: MenuItem? = null

    private val UI_ANIMATION_DURATION = 300L

    private var w_318: Int = 0
    private var w_240: Int = 0
    private var w_left: Int = 0

    private var isLeftToolbarOpen = false

    enum class LeftToolbarType {
        NONE, THUMBNAIL, BOOKMARK, OUTLINE, SEARCH
    }
    private var leftToolbarType = LeftToolbarType.NONE

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_reader)
        setSupportActionBar(toolbar_readerActivity)

        val displayMetrics = DisplayMetrics()
        windowManager.defaultDisplay.getMetrics(displayMetrics)
        val width = Math.min(DensityUtil.getScreenWidthPx(baseContext), DensityUtil.getScreenHeightPx(baseContext))
        w_318 = 318 * width / 800
        w_240 = 240 * width / 800
        w_left = resources.getDimension(R.dimen.reader_left_right_toolbar_icon_width).toInt()

        cloneOriginConstraintSet()
        setupToolbar()
        setupLeftToolbar()
        setupRightSideToolbar()
        setupBottomToolbar()
        setupViewerEditView()

        val factory = ReaderViewModelFactory()
        viewModel = ViewModelProviders.of(this, factory).get(ReaderViewModel::class.java)
        viewModel.isOpenedFileLiveData.observe(this, Observer(this::onIsOpenedFileUpdate))
        viewModel.fileNameLiveData.observe(this, Observer { tv_readerActivity_title.text = it })
        viewModel.isOpenedFileLiveData.value?.also { isOpened ->
            if (isOpened) return@also
            val filePath = intent.getStringExtra(KEY_FILE_ABSOLUTE)
            val uri = Uri.parse(filePath)
            viewModel.openPdfFile(this, uri, intent.type)
        }
        viewModel.pageIndexLiveData.observe(this, Observer(this::onPageIndexChanged))
        viewModel.isPageInBookmarksLiveData.observe(this, Observer(this::onIsPageInBookmarksChanged))
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.reader_more, menu)
        menuItemBookmark = menu?.findItem(R.id.item_reader_bookmark)
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
            menu?.findItem(R.id.item_reader_more_print)?.isVisible = false
        }
        // TODO: Check is pdf file or epub file, these action support only pdf file
        val isPdf = true
        if (!isPdf) {
            menu?.apply {
                findItem(R.id.item_reader_more_text_reflow)?.isVisible = false
                findItem(R.id.item_reader_more_file_info)?.isVisible = false
                findItem(R.id.item_reader_more_print)?.isVisible = false
            }
        }
        return true
    }

    @SuppressLint("RestrictedApi")
    override fun onPrepareOptionsPanel(view: View?, menu: Menu?): Boolean {
        /** Force show action menu item icon **/
        menu?.also {
            if ("MenuBuilder" != it::javaClass.get().simpleName) return@also
            try {
                val method = it.javaClass.getDeclaredMethod("setOptionalIconsVisible", java.lang.Boolean.TYPE)
                method.isAccessible = true
                method.invoke(it, true)
            } catch (e: Exception) {
                // Do nothing
            }
        }
        return super.onPrepareOptionsPanel(view, menu)
    }

    private fun cloneOriginConstraintSet() {
        if (!isBelowKitkat()) {
            originConstraintSet = ConstraintSet().apply {
                clone(constrainLayout_readerActivity_root)
            }
        }
    }

    private fun onIsOpenedFileUpdate(isOpened: Boolean?) {
        if (isOpened == null) return
        val container = viewGroup_readerActivity_container
        container.removeAllViews()
        if (!isOpened) return
        val context = this
        val readerView = object : KMPDFReaderView(context) {
            override fun onTapMainDocArea() {
                super.onTapMainDocArea()
                if (isBelowKitkat()) {
                    isHideToolbar = toolbar_readerActivity.visibility != View.VISIBLE
                            || viewGroup_readerActivity_bottomToolbar.visibility != View.VISIBLE
                            || viewGroup_readerActivity_leftToolbar.visibility != View.VISIBLE
                            || viewGroup_readerActivity_rightToolbar.visibility != View.VISIBLE
                }
                when (isHideToolbar) {
                    true -> showAllToolbars()
                    false -> hideAllToolbars()
                }
                isHideToolbar = !isHideToolbar
            }

            override fun onMoveToChild(pageIndex: Int) {
                super.onMoveToChild(pageIndex)
                viewModel.setPageIndex(pageIndex)
                updateThumbnailViewSelectedPage()
            }

            override fun onScroll(e1: MotionEvent?, e2: MotionEvent?, distanceX: Float, distanceY: Float): Boolean {
                if (isBelowKitkat()) {
                    isHideToolbar = toolbar_readerActivity.visibility != View.VISIBLE
                            || viewGroup_readerActivity_bottomToolbar.visibility != View.VISIBLE
                            || viewGroup_readerActivity_leftToolbar.visibility != View.VISIBLE
                            || viewGroup_readerActivity_rightToolbar.visibility != View.VISIBLE
                }
                if (!isHideToolbar) {
                    hideAllToolbars()
                    isHideToolbar = false
                }
                return super.onScroll(e1, e2, distanceX, distanceY)
            }
        }
        viewModel.setReaderView(readerView)
        container.addView(readerView)
    }

    private fun onPageIndexChanged(pageIndex: Int?) {
        pageIndex?.let {
            viewModel.setBookmarkDisplay(pageIndex)
        }
    }

    private fun onIsPageInBookmarksChanged(isPageInBookmarks: Boolean?) {
        isPageInBookmarks?.let {
            if (it) {
                menuItemBookmark?.icon = ContextCompat.getDrawable(this, R.drawable.ic_bookmark)
            } else {
                menuItemBookmark?.icon = ContextCompat.getDrawable(this, R.drawable.ic_bookmark_border)
            }
        }
    }

    private fun isBelowKitkat(): Boolean {
        return true
//        return Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT
    }

    private fun showAllToolbars() {
        if (isBelowKitkat()) {
            AnimationUtil.showViewFromTopToBottom(toolbar_readerActivity, UI_ANIMATION_DURATION)
            AnimationUtil.showViewFromBottomToTop(viewGroup_readerActivity_bottomToolbar, UI_ANIMATION_DURATION)
            AnimationUtil.showViewFromLeftToRight(viewGroup_readerActivity_leftToolbar, UI_ANIMATION_DURATION)
            AnimationUtil.showViewFromRightToLeft(viewGroup_readerActivity_rightToolbar, UI_ANIMATION_DURATION)
        } else {
            constrainLayout_readerActivity_root.applyConstraintSet(originConstraintSet, UI_ANIMATION_DURATION)
        }
    }

    private fun hideAllToolbars() {
        if (isBelowKitkat()) {
            AnimationUtil.hideViewFromBottomToTop(toolbar_readerActivity, UI_ANIMATION_DURATION)
            AnimationUtil.hideViewFromTopToBottom(viewGroup_readerActivity_bottomToolbar, UI_ANIMATION_DURATION)
            AnimationUtil.hideViewFromRightToLeft(viewGroup_readerActivity_leftToolbar, UI_ANIMATION_DURATION)
            AnimationUtil.hideViewFromLeftToRight(viewGroup_readerActivity_rightToolbar, UI_ANIMATION_DURATION)
            viewerEditView.visibility = View.GONE
            hideSearchViewSoftKeyboard()
        } else {
            constrainLayout_readerActivity_root.applyConstraintSet(this, R.layout.activity_reader_hide_all, UI_ANIMATION_DURATION)
        }
    }

    private fun hideTopLeftBottomToolbars() {
        if (isBelowKitkat()) {
            AnimationUtil.hideViewFromBottomToTop(toolbar_readerActivity, UI_ANIMATION_DURATION)
            AnimationUtil.hideViewFromTopToBottom(viewGroup_readerActivity_bottomToolbar, UI_ANIMATION_DURATION)
            AnimationUtil.hideViewFromRightToLeft(viewGroup_readerActivity_leftToolbar, UI_ANIMATION_DURATION)
            hideSearchViewSoftKeyboard()
        } else {
            constrainLayout_readerActivity_root.applyConstraintSet(this, R.layout.activity_reader_hide_top_left_bottom, UI_ANIMATION_DURATION)
        }
    }

    private fun updateThumbnailViewSelectedPage() {
        val view = linearLayout_readerActivity_leftToolbarContainer.getChildAt(0)
        if (view is ThumbnailView) {
            val currentPage = viewModel.pdfInfoHandler.getCurrentPage()
            view.onScrollToPosition(currentPage, true)
        }
    }

    private fun updateBookmarkView() {
        val view = linearLayout_readerActivity_leftToolbarContainer.getChildAt(0)
        if (view is BookmarkView) {
            view.updateBookmark()
        }
    }

    private fun setupToolbar() {
        toolbar_readerActivity.setOnMenuItemClickListener {
            when (it.itemId) {
                R.id.item_reader_bookmark -> onClickBookmark()
                R.id.item_reader_more_share -> onClickShare()
                R.id.item_reader_more_text_reflow -> onClickTextReflow()
                R.id.item_reader_more_file_info -> onClickFileInfo()
                R.id.item_reader_more_print -> onClickPrint()
                R.id.item_reader_more_user_guide -> onClickUserGuide()
            }
            return@setOnMenuItemClickListener true
        }
    }

    private fun onClickBookmark() {
        viewModel.isPageInBookmarksLiveData.value?.let {
            if (!it) {
                showAddBookmarkDialog()
            } else {
                showDeleteBookmarkDialog()
            }
        }
    }

    private fun showAddBookmarkDialog() {
        val alertDialogBuilder = AlertDialog.Builder(this)
        val editText = EditText(this)
        val layoutParams =
                LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT)

        editText.layoutParams = layoutParams
        val defaultTitle = getString(R.string.dialogAddBookmark_page) + " " + (viewModel.pdfInfoHandler.getCurrentPage() + 1)
        editText.setText(defaultTitle, TextView.BufferType.EDITABLE)
        editText.setSelection(0, defaultTitle.length)

        alertDialogBuilder.setTitle(getString(R.string.reader_alert_dialog_title_add_bookmark))
        alertDialogBuilder.setView(editText)
        alertDialogBuilder.setPositiveButton(getString(R.string.reader_alert_dialog_button_confirm)) { dialog, which ->
            viewModel.addBookmark(editText.text.toString())
            updateBookmarkView()
        }
        alertDialogBuilder.setNegativeButton(getString(R.string.reader_alert_dialog_button_cancel)) { dialog, which ->
        }
        alertDialogBuilder.create().show()
        editText.requestFocus()
    }

    private fun getBookmarkTitle(page: Int): String {
        val bookmarks = viewModel.bookmarkHandler.getBookmarks()
        for (bookmark in bookmarks) {
            if (bookmark.pageNum == page) {
                return bookmark.title
            }
        }
        return ""
    }

    private fun showDeleteBookmarkDialog() {
        val alertDialogBuilder = AlertDialog.Builder(this)
        alertDialogBuilder.setTitle(getString(R.string.reader_alert_dialog_title_delete_bookmark))
        val bookmarkTitle = getBookmarkTitle(viewModel.pdfInfoHandler.getCurrentPage())
        val message = String.format(getString(R.string.reader_alert_dialog_message_delete_bookmark), bookmarkTitle)
        alertDialogBuilder.setMessage(message)
        alertDialogBuilder.setPositiveButton(getString(R.string.reader_alert_dialog_button_confirm)) { dialog, which ->
            viewModel.deleteBookmark()
            updateBookmarkView()
        }
        alertDialogBuilder.setNegativeButton(getString(R.string.reader_alert_dialog_button_cancel)) { dialog, which ->
        }
        alertDialogBuilder.create().show()
    }

    private fun hideSearchViewSoftKeyboard() {
        val view = linearLayout_readerActivity_leftToolbarContainer.getChildAt(0)
        if (view is SearchView) {
            view.hideSoftKeyboard()
        }
    }

    private fun setupLeftToolbar() {
        viewGroup_readerActivity_leftToolbar.setScroll(false)
        setLeftToolbarWidth(w_240)
        viewGroup_readerActivity_leftToolbar.smoothScrollTo(w_240, 0, 0)
        val child = layoutInflater.inflate(R.layout.view_thumbnail, null)
        linearLayout_readerActivity_leftToolbarContainer.addView(child)
        cloneOriginConstraintSet()
    }

    private fun setupRightSideToolbar() {
        iv_readerActivity_setting.setOnClickListener {
            startActivity(Intent(this, ViewerSettingActivity::class.java))
        }
    }

    private fun setupBottomToolbar() {
        val context = this
        /** Set buttons color **/
        val normalColor = R.color.reader_bottom_toolbar_bottom_color_normal
        val pressColor = R.color.reader_bottom_toolbar_bottom_color_press
        Utils.setTintDrawableList(context, ib_readerActivity_bottomToolbarPrevious, R.drawable.ic_chevron_left, normalColor, pressColor)
        Utils.setTintDrawableList(context, ib_readerActivity_bottomToolbarNext, R.drawable.ic_chevron_right, normalColor, pressColor)
        Utils.setTintDrawableList(context, ib_readerActivity_bottomToolbarBookmark, R.drawable.ic_bookmark_border, normalColor, pressColor)
        Utils.setTintDrawableList(context, ib_readerActivity_bottomToolbarViewAll, R.drawable.ic_view_all, normalColor, pressColor)
        Utils.setTintDrawableList(context, ib_readerActivity_bottomToolbarKdanCloud, R.drawable.ic_kdan_cloud, normalColor, pressColor)
    }

    private fun setupViewerEditView() {

        ib_readerActivity_bottomToolbarKdanCloud.setOnClickListener {
            viewerEditView.visibility = View.VISIBLE
        }

        viewerEditView.apply {
            onViewerEditTabAddButtonClickListener = object : ViewerEditView.OnViewerEditTabAddButtonClickListener {
                override fun onTabTextBoxAddButtonClick(textBoxTabView: TextBoxTabView) {
                    hideAllToolbars()
                    viewModel.setTextBoxAttribute(textBoxTabView.getTextBoxAttribute())
                }

                override fun onTabStampAddButtonClick(stampTabView: StampTabView) {
                    hideAllToolbars()
                    viewModel.setStampAttribute(stampTabView.getStampAttribute())
                }

                override fun onTabShapeAddButtonClick(shapeTabView: ShapeTabView) {
                    hideAllToolbars()
                    viewModel.setShapeAttribute(shapeTabView.getShapeAttribute())
                }
            }
        }
    }

    private fun setLeftToolbarWidth(width: Int) {
        var params = viewGroup_readerActivity_leftToolbar.layoutParams as ConstraintLayout.LayoutParams
        params.width = width + w_left
        params.height = 0
        viewGroup_readerActivity_leftToolbar.layoutParams = params

        params = linearLayout_readerActivity_leftToolbarContainer.layoutParams as ConstraintLayout.LayoutParams
        params.width = width
        linearLayout_readerActivity_leftToolbarContainer.layoutParams = params
    }

    private fun changeLeftToolbarType(type: LeftToolbarType) {
        iv_readerActivity_thumbnail.setImageResource(R.drawable.ic_pagelist_thumbnail_nor)
        iv_readerActivity_bookmark.setImageResource(R.drawable.ic_pagelist_bookmk_nor)
        iv_readerActivity_outline.setImageResource(R.drawable.ic_pagelist_outline_nor)
        iv_readerActivity_search.setImageResource(R.drawable.ic_pagelist_search_nor)

        val width = when (type) {
            LeftToolbarType.THUMBNAIL -> w_240
            else -> w_318
        }
        setLeftToolbarWidth(width)

        isLeftToolbarOpen = (!isLeftToolbarOpen || leftToolbarType != type)
        if (isLeftToolbarOpen)
            viewGroup_readerActivity_leftToolbar.smoothScrollTo(0, 0, UI_ANIMATION_DURATION.toInt())
        else
            viewGroup_readerActivity_leftToolbar.smoothScrollTo(width, 0, UI_ANIMATION_DURATION.toInt())
        cloneOriginConstraintSet()
    }

    private fun onThumbnailClick() {
        val type = LeftToolbarType.THUMBNAIL
        changeLeftToolbarType(type)
        if (isLeftToolbarOpen) {
            if (leftToolbarType != type) {
                linearLayout_readerActivity_leftToolbarContainer.removeAllViews()
                val thumbnailView = ThumbnailView(this)
                thumbnailView.setHandlers(viewModel.pdfInfoHandler, viewModel.thumbnailHandler)
                linearLayout_readerActivity_leftToolbarContainer.addView(thumbnailView)
            }
            iv_readerActivity_thumbnail.setImageResource(R.drawable.ic_pagelist_thumbnail_h)
        } else {
            iv_readerActivity_thumbnail.setImageResource(R.drawable.ic_pagelist_thumbnail_nor)
        }
        leftToolbarType = type
    }

    private fun onBookmarkClick() {
        val type = LeftToolbarType.BOOKMARK
        changeLeftToolbarType(type)
        if (isLeftToolbarOpen) {
            if (leftToolbarType != type) {
                linearLayout_readerActivity_leftToolbarContainer.removeAllViews()
                val bookmarkView = BookmarkView(this)
                bookmarkView.setHandlers(viewModel.pdfInfoHandler, viewModel.thumbnailHandler, viewModel.bookmarkHandler)
                linearLayout_readerActivity_leftToolbarContainer.addView(bookmarkView)
            }
            iv_readerActivity_bookmark.setImageResource(R.drawable.ic_pagelist_bookmk_h)
        } else {
            iv_readerActivity_bookmark.setImageResource(R.drawable.ic_pagelist_bookmk_nor)
        }
        leftToolbarType = type
    }

    private fun onOutlineClick() {
        val type = LeftToolbarType.OUTLINE
        changeLeftToolbarType(type)
        if (isLeftToolbarOpen) {
            if (leftToolbarType != type) {
                linearLayout_readerActivity_leftToolbarContainer.removeAllViews()
                val outlineView = OutlineView(this)
                outlineView.setHandlers(viewModel.pdfInfoHandler, viewModel.outlineHandler)
                linearLayout_readerActivity_leftToolbarContainer.addView(outlineView)
            }
            iv_readerActivity_outline.setImageResource(R.drawable.ic_pagelist_outline_h)
        } else {
            iv_readerActivity_outline.setImageResource(R.drawable.ic_pagelist_outline_nor)
        }
        leftToolbarType = type
    }

    private fun onSearchClick() {
        val type = LeftToolbarType.SEARCH
        changeLeftToolbarType(type)
        if (isLeftToolbarOpen) {
            if (leftToolbarType != type) {
                linearLayout_readerActivity_leftToolbarContainer.removeAllViews()
                val searchView = SearchView(this)
                searchView.setHandlers(viewModel.pdfInfoHandler, viewModel.searchHandler)
                linearLayout_readerActivity_leftToolbarContainer.addView(searchView)
            }
            iv_readerActivity_search.setImageResource(R.drawable.ic_pagelist_search_h)
        } else {
            iv_readerActivity_search.setImageResource(R.drawable.ic_pagelist_search_nor)
            hideSearchViewSoftKeyboard()
        }
        leftToolbarType = type
    }

    fun onClick(view: View) {
        when (view.id) {
            R.id.iv_readerActivity_thumbnail -> {
                onThumbnailClick()
            }
            R.id.iv_readerActivity_bookmark -> {
                onBookmarkClick()
            }
            R.id.iv_readerActivity_outline -> {
                onOutlineClick()
            }
            R.id.iv_readerActivity_search -> {
                onSearchClick()
            }
            R.id.iv_readerActivity_fullScreen -> {
                hideTopLeftBottomToolbars()
            }
            else -> {

            }
        }
    }
}
