/*
 * Copyright 2019 Ross Binden
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.rpkit.store.bukkit.database.table

import com.rpkit.core.database.Database
import com.rpkit.core.database.Table
import com.rpkit.store.bukkit.RPKStoresBukkit
import com.rpkit.store.bukkit.storeitem.RPKPermanentStoreItem
import com.rpkit.store.bukkit.storeitem.RPKPermanentStoreItemImpl
import com.rpkit.stores.bukkit.database.jooq.rpkit.Tables.RPKIT_PERMANENT_STORE_ITEM
import com.rpkit.stores.bukkit.database.jooq.rpkit.Tables.RPKIT_STORE_ITEM
import org.ehcache.config.builders.CacheConfigurationBuilder
import org.ehcache.config.builders.ResourcePoolsBuilder
import org.jooq.impl.DSL.constraint
import org.jooq.impl.SQLDataType


class RPKPermanentStoreItemTable(database: Database, private val plugin: RPKStoresBukkit): Table<RPKPermanentStoreItem>(database, RPKPermanentStoreItem::class) {

    private val cache = if (plugin.config.getBoolean("caching.rpkit_permanent_store_item.id.enabled")) {
        database.cacheManager.createCache("rpkit-stores-bukkit.rpkit_permanent_store_item.id",
                CacheConfigurationBuilder.newCacheConfigurationBuilder(Int::class.javaObjectType, RPKPermanentStoreItem::class.java,
                        ResourcePoolsBuilder.heap(plugin.config.getLong("caching.rpkit_permanent_store_item.id.size"))).build())
    } else {
        null
    }

    override fun create() {
        database.create
                .createTableIfNotExists(RPKIT_PERMANENT_STORE_ITEM)
                .column(RPKIT_PERMANENT_STORE_ITEM.ID, SQLDataType.INTEGER.identity(true))
                .column(RPKIT_PERMANENT_STORE_ITEM.STORE_ITEM_ID, SQLDataType.INTEGER)
                .constraints(
                        constraint("pk_rpkit_permanent_store_item").primaryKey(RPKIT_PERMANENT_STORE_ITEM.ID)
                )
                .execute()
    }

    override fun applyMigrations() {
        if (database.getTableVersion(this) == null) {
            database.setTableVersion(this, "1.6.0")
        }

    }

    override fun insert(entity: RPKPermanentStoreItem): Int {
        val id = database.getTable(RPKStoreItemTable::class).insert(entity)
        database.create
                .insertInto(
                        RPKIT_PERMANENT_STORE_ITEM,
                        RPKIT_PERMANENT_STORE_ITEM.STORE_ITEM_ID
                )
                .values(
                        id
                )
                .execute()
        entity.id = id
        cache?.put(id, entity)
        return id
    }

    override fun update(entity: RPKPermanentStoreItem) {
        database.getTable(RPKStoreItemTable::class).update(entity)
        cache?.put(entity.id, entity)
    }

    override fun get(id: Int): RPKPermanentStoreItem? {
        if (cache?.containsKey(id) == true) {
            return cache[id]
        } else {
            val result = database.create
                    .select(
                            RPKIT_STORE_ITEM.PLUGIN,
                            RPKIT_STORE_ITEM.IDENTIFIER,
                            RPKIT_STORE_ITEM.DESCRIPTION,
                            RPKIT_STORE_ITEM.COST
                    )
                    .from(
                            RPKIT_STORE_ITEM,
                            RPKIT_PERMANENT_STORE_ITEM
                    )
                    .where(RPKIT_STORE_ITEM.ID.eq(id))
                    .and(RPKIT_STORE_ITEM.ID.eq(RPKIT_PERMANENT_STORE_ITEM.STORE_ITEM_ID))
                    .fetchOne() ?: return null
            val storeItem = RPKPermanentStoreItemImpl(
                    id,
                    result[RPKIT_STORE_ITEM.PLUGIN],
                    result[RPKIT_STORE_ITEM.IDENTIFIER],
                    result[RPKIT_STORE_ITEM.DESCRIPTION],
                    result[RPKIT_STORE_ITEM.COST]
            )
            cache?.put(id, storeItem)
            return storeItem
        }
    }

    override fun delete(entity: RPKPermanentStoreItem) {
        database.getTable(RPKStoreItemTable::class).delete(entity)
        database.create
                .deleteFrom(RPKIT_PERMANENT_STORE_ITEM)
                .where(RPKIT_PERMANENT_STORE_ITEM.STORE_ITEM_ID.eq(entity.id))
                .execute()
        cache?.remove(entity.id)
    }

}