package net.pokeranalytics.android.model.interfaces

import android.content.Context
import io.realm.Realm
import io.realm.RealmModel
import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.ModelException
import net.pokeranalytics.android.ui.view.RowRepresentable

enum class SaveValidityStatus {
	VALID,
	ALREADY_EXISTS,
	DATA_INVALID;
}

enum class DeleteValidityStatus {
	VALID,
	INVALID,
	SESSIONS_LINKED,
	TRANSACTIONS_LINKED;
}

/**
 * An interface to group object which are managed by the database
 */
interface Manageable : Savable, Deletable, Editable

interface NameManageable : Manageable {
	var name: String

	override fun isValidForSave(): Boolean {
		return this.name.isNotEmpty()
	}

	override fun alreadyExists(realm: Realm): Boolean {
		return realm.where(this::class.java).equalTo("name", this.name).and().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.relationship_error
	}
}


/**
 * An interface associate a unique uniqueIdentifier to an object
 */
interface Identifiable : RealmModel {

	/**
	 * A unique uniqueIdentifier getter
	 */
	var id: String
}

/**
 * An interface to update the fields of an object
 */
interface Editable : Identifiable {
	/**
	 * a method to handle the modification of the object.
	 * Through [RowRepresentable] the object is able to update the right variable with the new value.
	 */
	fun updateValue(value: Any?, row: RowRepresentable)
}

/**
 * An interface to easily handle the validity of any object we want to save
 */
interface Savable : Identifiable {

	fun isValidForSave(): Boolean
	fun alreadyExists(realm: Realm): Boolean

	/**
	 * A method to define if an object is safe for saving in database
	 */
	fun getSaveValidityStatus(realm: Realm): SaveValidityStatus {
		if (!isValidForSave()) {
			return SaveValidityStatus.DATA_INVALID
		}

		if (alreadyExists(realm)) {
			return SaveValidityStatus.ALREADY_EXISTS
		}

		return SaveValidityStatus.VALID
	}


	/**
	 * A method to get the reason why the object can't be saved
	 */
	fun getFailedSaveMessage(status: SaveValidityStatus): Int
}


/**
 * An interface to easily handle the validity of any object we want to delete
 */
interface Deletable : Identifiable {

	/**
	 * A method to define if an object is safe for deletion in database
	 */
	fun isValidForDelete(realm: Realm): Boolean


	fun getDeleteStatus(context: Context, realm: Realm): DeleteValidityStatus {
		if (!isValidForDelete(realm)) {
			return DeleteValidityStatus.INVALID
		}
		return DeleteValidityStatus.VALID
	}

	/**
	 * A method to get the reason why the object can't be deleted
	 */
	fun getFailedDeleteMessage(status: DeleteValidityStatus): Int

	/**
	 * A method to override if we need to delete linked objects or other stuff
	 */
	fun deleteDependencies(realm: Realm) {}

}