@file:OptIn(ExperimentalTime::class)
@file:Suppress("HardCodedStringLiteral")

package eu.gaudian.translator.model.db

import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import androidx.sqlite.db.SupportSQLiteDatabase
import eu.gaudian.translator.model.VocabularyItem
import eu.gaudian.translator.model.VocabularyItemState
import kotlin.time.ExperimentalTime

@OptIn(ExperimentalTime::class)
@Database(
    entities = [
        VocabularyItem::class,
        VocabularyItemState::class,
        VocabularyCategoryEntity::class,
        CategoryMappingEntity::class,
        StageMappingEntity::class,
        DailyStatEntity::class
    ],
    version = 3
)

@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {

    abstract fun vocabularyItemDao(): VocabularyItemDao
    abstract fun vocabularyStateDao(): VocabularyStateDao
    abstract fun categoryDao(): CategoryDao
    abstract fun mappingDao(): MappingDao
    abstract fun dailyStatDao(): DailyStatDao

    companion object {
        @Volatile
        private var INSTANCE: AppDatabase? = null

        private val MIGRATION_1_2 = object : androidx.room.migration.Migration(1, 2) {
            override fun migrate(db: SupportSQLiteDatabase) {
                db.execSQL("ALTER TABLE vocabulary_items ADD COLUMN zipfFrequency REAL")
            }
        }

        private val MIGRATION_2_3 = object : androidx.room.migration.Migration(2, 3) {
            override fun migrate(db: SupportSQLiteDatabase) {
                // Create new table with the updated schema
                db.execSQL(
                    "CREATE TABLE IF NOT EXISTS `vocabulary_items_new` (" +
                            "`id` INTEGER NOT NULL, " +
                            "`languageFirstId` INTEGER, " +
                            "`languageSecondId` INTEGER, " +
                            "`wordFirst` TEXT NOT NULL, " +
                            "`wordSecond` TEXT NOT NULL, " +
                            "`createdAt` INTEGER, " +
                            "`features` TEXT, " +
                            "`zipfFrequencyFirst` REAL, " +
                            "`zipfFrequencySecond` REAL, " +
                            "PRIMARY KEY(`id`)"
                            + ")"
                )
                // Copy data from old table mapping zipfFrequency to zipfFrequencyFirst
                db.execSQL(
                    "INSERT INTO `vocabulary_items_new` (" +
                            "id, languageFirstId, languageSecondId, wordFirst, wordSecond, createdAt, features, zipfFrequencyFirst, zipfFrequencySecond" +
                            ") SELECT id, languageFirstId, languageSecondId, wordFirst, wordSecond, createdAt, features, zipfFrequency, NULL FROM `vocabulary_items`"
                )
                // Drop old table
                db.execSQL("DROP TABLE `vocabulary_items`")
                // Rename new table to old name
                db.execSQL("ALTER TABLE `vocabulary_items_new` RENAME TO `vocabulary_items`")
            }
        }

        fun getDatabase(context: Context): AppDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    AppDatabase::class.java,
                    "vocabulary_database"
                ).addMigrations(MIGRATION_1_2, MIGRATION_2_3).build()
                INSTANCE = instance
                instance
            }
        }
    }
}