/*
 * 				Twidere - Twitter client for Android
 * 
 *  Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.mariotaku.twidere.fragment

import android.app.Dialog
import android.content.ContentValues
import android.os.Bundle
import androidx.fragment.app.FragmentManager
import androidx.appcompat.app.AlertDialog
import com.twitter.Extractor
import org.mariotaku.kpreferences.get
import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_STATUS
import org.mariotaku.twidere.constant.nameFirstKey
import org.mariotaku.twidere.extension.applyTheme
import org.mariotaku.twidere.extension.onShow
import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.ParcelableUserMention
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.provider.TwidereDataStore.Filters
import org.mariotaku.twidere.util.ContentValuesCreator
import org.mariotaku.twidere.util.HtmlEscapeHelper
import org.mariotaku.twidere.util.ParseUtils
import org.mariotaku.twidere.util.UserColorNameManager
import org.mariotaku.twidere.util.content.ContentResolverUtils
import java.util.*

class AddStatusFilterDialogFragment : BaseDialogFragment() {

    private val extractor = Extractor()
    private var filterItems: Array<FilterItemInfo>? = null

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val builder = AlertDialog.Builder(context!!)
        filterItems = filterItemsInfo
        val entries = arrayOfNulls<String>(filterItems!!.size)
        val nameFirst = preferences[nameFirstKey]
        for (i in 0 until entries.size) {
            val info = filterItems!![i]
            when (info.type) {
                FilterItemInfo.FILTER_TYPE_USER -> {
                    entries[i] = getString(R.string.user_filter_name, getName(userColorNameManager,
                            info.value, nameFirst))
                }
                FilterItemInfo.FILTER_TYPE_KEYWORD -> {
                    entries[i] = getString(R.string.keyword_filter_name, getName(userColorNameManager,
                            info.value, nameFirst))
                }
                FilterItemInfo.FILTER_TYPE_SOURCE -> {
                    entries[i] = getString(R.string.source_filter_name, getName(userColorNameManager,
                            info.value, nameFirst))
                }
            }
        }
        builder.setTitle(R.string.action_add_to_filter)
        builder.setMultiChoiceItems(entries, null, null)
        builder.setPositiveButton(android.R.string.ok) { dialog, _ ->
            val alertDialog = dialog as AlertDialog
            val checkPositions = alertDialog.listView.checkedItemPositions

            val userKeys = HashSet<UserKey>()
            val keywords = HashSet<String>()
            val sources = HashSet<String>()
            val userValues = ArrayList<ContentValues>()
            val keywordValues = ArrayList<ContentValues>()
            val sourceValues = ArrayList<ContentValues>()
            loop@ for (i in 0 until checkPositions.size()) {
                if (!checkPositions.valueAt(i)) {
                    continue@loop
                }
                val info = filterItems!![checkPositions.keyAt(i)]
                val value = info.value
                if (value is ParcelableUserMention) {
                    userKeys.add(value.key)
                    userValues.add(ContentValuesCreator.createFilteredUser(value))
                } else if (value is UserItem) {
                    userKeys.add(value.key)
                    userValues.add(createFilteredUser(value))
                } else if (info.type == FilterItemInfo.FILTER_TYPE_KEYWORD) {
                    val keyword = ParseUtils.parseString(value)
                    keywords.add(keyword)
                    val values = ContentValues()
                    values.put(Filters.Keywords.VALUE, "#$keyword")
                    keywordValues.add(values)
                } else if (info.type == FilterItemInfo.FILTER_TYPE_SOURCE) {
                    val source = ParseUtils.parseString(value)
                    sources.add(source)
                    val values = ContentValues()
                    values.put(Filters.Sources.VALUE, source)
                    sourceValues.add(values)
                }
            }
            context?.contentResolver?.let { resolver ->
                ContentResolverUtils.bulkDelete(resolver, Filters.Users.CONTENT_URI,
                        Filters.Users.USER_KEY, false, userKeys, null, null)
                ContentResolverUtils.bulkDelete(resolver, Filters.Keywords.CONTENT_URI,
                        Filters.Keywords.VALUE, false, keywords, null, null)
                ContentResolverUtils.bulkDelete(resolver, Filters.Sources.CONTENT_URI,
                        Filters.Sources.VALUE, false, sources, null, null)
                ContentResolverUtils.bulkInsert(resolver, Filters.Users.CONTENT_URI, userValues)
                ContentResolverUtils.bulkInsert(resolver, Filters.Keywords.CONTENT_URI, keywordValues)
                ContentResolverUtils.bulkInsert(resolver, Filters.Sources.CONTENT_URI, sourceValues)
            }
        }
        builder.setNegativeButton(android.R.string.cancel, null)
        val dialog = builder.create()
        dialog.onShow { it.applyTheme() }
        return dialog
    }

    private val filterItemsInfo: Array<FilterItemInfo>
        get() {
            val args = arguments
            if (args == null || !args.containsKey(EXTRA_STATUS)) return emptyArray()
            val status = args.getParcelable<ParcelableStatus>(EXTRA_STATUS) ?: return emptyArray()
            val list = ArrayList<FilterItemInfo>()
            if (status.is_retweet && status.retweeted_by_user_key != null) {
                list.add(FilterItemInfo(FilterItemInfo.FILTER_TYPE_USER,
                        UserItem(status.retweeted_by_user_key!!, status.retweeted_by_user_name,
                                status.retweeted_by_user_screen_name)))
            }
            if (status.is_quote && status.quoted_user_key != null) {
                list.add(FilterItemInfo(FilterItemInfo.FILTER_TYPE_USER,
                        UserItem(status.quoted_user_key!!, status.quoted_user_name,
                                status.quoted_user_screen_name)))
            }
            list.add(FilterItemInfo(FilterItemInfo.FILTER_TYPE_USER, UserItem(status.user_key,
                    status.user_name, status.user_screen_name)))
            val mentions = status.mentions
            if (mentions != null) {
                for (mention in mentions) {
                    if (mention.key != status.user_key) {
                        list.add(FilterItemInfo(FilterItemInfo.FILTER_TYPE_USER, mention))
                    }
                }
            }
            val hashtags = HashSet<String>()
            hashtags.addAll(extractor.extractHashtags(status.text_plain))
            for (hashtag in hashtags) {
                list.add(FilterItemInfo(FilterItemInfo.FILTER_TYPE_KEYWORD, hashtag))
            }
            val source = status.source?.let(HtmlEscapeHelper::toPlainText)
            if (source != null) {
                list.add(FilterItemInfo(FilterItemInfo.FILTER_TYPE_SOURCE, source))
            }
            return list.toTypedArray()
        }

    private fun getName(manager: UserColorNameManager, value: Any, nameFirst: Boolean): String {
        if (value is ParcelableUserMention) {
            return manager.getDisplayName(value.key, value.name, value.screen_name, nameFirst)
        } else if (value is UserItem) {
            return manager.getDisplayName(value.key, value.name, value.screen_name, nameFirst)
        } else
            return ParseUtils.parseString(value)
    }

    internal data class FilterItemInfo(
            val type: Int,
            val value: Any
    ) {

        companion object {

            internal const val FILTER_TYPE_USER = 1
            internal const val FILTER_TYPE_KEYWORD = 2
            internal const val FILTER_TYPE_SOURCE = 3
        }

    }

    internal data class UserItem(
            val key: UserKey,
            val name: String,
            val screen_name: String
    )

    companion object {

        val FRAGMENT_TAG = "add_status_filter"

        private fun createFilteredUser(item: UserItem): ContentValues {
            val values = ContentValues()
            values.put(Filters.Users.USER_KEY, item.key.toString())
            values.put(Filters.Users.NAME, item.name)
            values.put(Filters.Users.SCREEN_NAME, item.screen_name)
            return values
        }

        fun show(fm: FragmentManager, status: ParcelableStatus): AddStatusFilterDialogFragment {
            val args = Bundle()
            args.putParcelable(EXTRA_STATUS, status)
            val f = AddStatusFilterDialogFragment()
            f.arguments = args
            f.show(fm, FRAGMENT_TAG)
            return f
        }
    }

}
