package net.pokeranalytics.android.model.realm

import android.content.Context
import android.text.InputType
import io.realm.Realm
import io.realm.RealmObject
import io.realm.RealmResults
import io.realm.annotations.Ignore
import io.realm.annotations.LinkingObjects
import io.realm.annotations.PrimaryKey
import io.realm.kotlin.where
import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.ModelException
import net.pokeranalytics.android.model.interfaces.DeleteValidityStatus
import net.pokeranalytics.android.model.interfaces.NameManageable
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.extensions.toCurrency
import java.text.NumberFormat
import java.util.*
import java.util.Currency


open class CustomFieldEntry : RealmObject(), NameManageable, RowRepresentable {

    @PrimaryKey
	override var id = UUID.randomUUID().toString()

	/**
	 * The order in the list
	 */
	var order: Int = 0

	/**
	 * The inverse relationship with CustomField
	 */
	@LinkingObjects("entries")
	val customFields: RealmResults<CustomField>? = null

	val customField: CustomField?
		get() {
			return this.customFields?.first()
		}

	/**
	 * The string value of the entry
	 */
	var value: String = ""

	/**
	 * The numeric value of the entry
	 */
    var numericValue: Double? = null

	@Ignore
    override var name: String = value
        get() { return value }

	@Ignore
	var isMovable: Boolean = false

	@Ignore
	override val viewType: Int = RowViewType.TITLE_VALUE_ACTION.ordinal

	override val imageRes: Int?
		get() {
			return if (isMovable) R.drawable.ic_reorder else null
		}

	override val imageTint: Int?
		get() {
			return R.color.kaki
		}

	@Ignore
	override val bottomSheetType: BottomSheetType = BottomSheetType.EDIT_TEXT

	override fun localizedTitle(context: Context): String {
		return context.getString(R.string.value)
	}

	override fun getDisplayName(context: Context): String {
		return if (value.isNotEmpty()) value else NULL_TEXT
	}

	override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? {
		val defaultValue: Any? by map
        return arrayListOf(
            RowRepresentableEditDescriptor(defaultValue, R.string.value, InputType.TYPE_CLASS_TEXT)
        )
	}

	override fun isValidForSave(): Boolean {
		return true
	}

	override fun alreadyExists(realm: Realm): Boolean {
		return realm.where(this::class.java).notEqualTo("id", this.id).findAll().isNotEmpty()
	}

	override fun getFailedSaveMessage(status: SaveValidityStatus): Int {
		throw ModelException("${this::class.java} getFailedSaveMessage for $status not handled")
	}

	override fun getFailedDeleteMessage(status: DeleteValidityStatus): Int {
		return R.string.cf_entry_delete_popup_message
	}

	override fun deleteDependencies(realm: Realm) {
		if (isValid) {
			val entries = realm.where<Session>().contains("customFieldEntries.id", id).findAll()
			entries.deleteAllFromRealm()
		}
	}

	override fun updateValue(value: Any?, row: RowRepresentable) {
        this.value = value as String? ?: ""
    }

	override fun isValidForDelete(realm: Realm): Boolean {
		if (realm.where<Session>().contains("customFieldEntries.id", id).findAll().isNotEmpty()) {
			return false
		}
		return true
	}

	/**
	 * Return the amount
	 */
	fun getFormattedValue(currency: Currency? = null): String {
		return when (customField?.type) {
			CustomField.Type.AMOUNT.uniqueIdentifier -> {
                numericValue?.toCurrency(currency) ?: run { NULL_TEXT }
			}
            CustomField.Type.NUMBER.uniqueIdentifier -> {
	            NumberFormat.getInstance().format(this.numericValue)
            }
			else -> {
				value
			}
		}
	}

}