package com.atridad.ascently.data.database

import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import com.atridad.ascently.data.database.dao.*
import com.atridad.ascently.data.model.*

@Database(
    entities = [Gym::class, Problem::class, ClimbSession::class, Attempt::class],
    version = 6,
    exportSchema = false,
)
@TypeConverters(Converters::class)
abstract class AscentlyDatabase : RoomDatabase() {

    abstract fun gymDao(): GymDao
    abstract fun problemDao(): ProblemDao
    abstract fun climbSessionDao(): ClimbSessionDao
    abstract fun attemptDao(): AttemptDao

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

        val MIGRATION_4_5 =
            object : Migration(4, 5) {
                override fun migrate(db: SupportSQLiteDatabase) {
                    val cursor = db.query("PRAGMA table_info(climb_sessions)")
                    val existingColumns = mutableSetOf<String>()

                    while (cursor.moveToNext()) {
                        val columnName = cursor.getString(cursor.getColumnIndexOrThrow("name"))
                        existingColumns.add(columnName)
                    }
                    cursor.close()

                    if (!existingColumns.contains("startTime")) {
                        db.execSQL("ALTER TABLE climb_sessions ADD COLUMN startTime TEXT")
                    }
                    if (!existingColumns.contains("endTime")) {
                        db.execSQL("ALTER TABLE climb_sessions ADD COLUMN endTime TEXT")
                    }
                    if (!existingColumns.contains("status")) {
                        db.execSQL(
                            "ALTER TABLE climb_sessions ADD COLUMN status TEXT NOT NULL DEFAULT 'COMPLETED'",
                        )
                    }

                    db.execSQL(
                        "UPDATE climb_sessions SET startTime = createdAt WHERE startTime IS NULL",
                    )
                    db.execSQL(
                        "UPDATE climb_sessions SET status = 'COMPLETED' WHERE status IS NULL OR status = ''",
                    )
                }
            }

        val MIGRATION_5_6 =
            object : Migration(5, 6) {
                override fun migrate(db: SupportSQLiteDatabase) {
                    // Add updatedAt column to attempts table
                    val cursor = db.query("PRAGMA table_info(attempts)")
                    val existingColumns = mutableSetOf<String>()

                    while (cursor.moveToNext()) {
                        val columnName = cursor.getString(cursor.getColumnIndexOrThrow("name"))
                        existingColumns.add(columnName)
                    }
                    cursor.close()

                    if (!existingColumns.contains("updatedAt")) {
                        db.execSQL(
                            "ALTER TABLE attempts ADD COLUMN updatedAt TEXT NOT NULL DEFAULT ''",
                        )
                        // Set updatedAt to createdAt for existing records
                        db.execSQL(
                            "UPDATE attempts SET updatedAt = createdAt WHERE updatedAt = ''",
                        )
                    }
                }
            }

        fun getDatabase(context: Context): AscentlyDatabase {
            return INSTANCE
                ?: synchronized(this) {
                    val instance =
                        Room.databaseBuilder(
                            context.applicationContext,
                            AscentlyDatabase::class.java,
                            "ascently_database",
                        )
                            .addMigrations(MIGRATION_4_5, MIGRATION_5_6)
                            .enableMultiInstanceInvalidation()
                            .fallbackToDestructiveMigration(false)
                            .build()
                    INSTANCE = instance
                    instance
                }
        }
    }
}
