package com.omixlab.lckcontrol.data.local

import androidx.room.Database
import androidx.room.RoomDatabase
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import com.omixlab.lckcontrol.data.local.dao.LinkedAccountDao
import com.omixlab.lckcontrol.data.local.dao.StreamPlanDao
import com.omixlab.lckcontrol.data.local.entity.LinkedAccountEntity
import com.omixlab.lckcontrol.data.local.entity.StreamDestinationEntity
import com.omixlab.lckcontrol.data.local.entity.StreamPlanEntity

@Database(
    entities = [
        LinkedAccountEntity::class,
        StreamPlanEntity::class,
        StreamDestinationEntity::class,
    ],
    version = 6,
    exportSchema = false,
)
abstract class LckDatabase : RoomDatabase() {
    abstract fun linkedAccountDao(): LinkedAccountDao
    abstract fun streamPlanDao(): StreamPlanDao

    companion object {
        val MIGRATION_1_2 = object : Migration(1, 2) {
            override fun migrate(db: SupportSQLiteDatabase) {
                // 1. Remove token columns from linked_accounts
                db.execSQL("""
                    CREATE TABLE linked_accounts_new (
                        serviceId TEXT NOT NULL PRIMARY KEY,
                        displayName TEXT NOT NULL,
                        accountId TEXT NOT NULL,
                        avatarUrl TEXT
                    )
                """.trimIndent())
                db.execSQL("""
                    INSERT INTO linked_accounts_new (serviceId, displayName, accountId, avatarUrl)
                    SELECT serviceId, displayName, accountId, avatarUrl FROM linked_accounts
                """.trimIndent())
                db.execSQL("DROP TABLE linked_accounts")
                db.execSQL("ALTER TABLE linked_accounts_new RENAME TO linked_accounts")

                // 2. Change stream_destinations.id from INTEGER to TEXT
                db.execSQL("""
                    CREATE TABLE stream_destinations_new (
                        id TEXT NOT NULL PRIMARY KEY,
                        planId TEXT NOT NULL,
                        service TEXT NOT NULL,
                        title TEXT NOT NULL,
                        description TEXT NOT NULL DEFAULT '',
                        privacyStatus TEXT NOT NULL DEFAULT 'public',
                        gameId TEXT NOT NULL DEFAULT '',
                        tags TEXT NOT NULL DEFAULT '',
                        rtmpUrl TEXT NOT NULL DEFAULT '',
                        streamKey TEXT NOT NULL DEFAULT '',
                        broadcastId TEXT NOT NULL DEFAULT '',
                        status TEXT NOT NULL DEFAULT 'PENDING',
                        FOREIGN KEY (planId) REFERENCES stream_plans(planId) ON DELETE CASCADE
                    )
                """.trimIndent())
                db.execSQL("CREATE INDEX index_stream_destinations_planId ON stream_destinations_new(planId)")
                db.execSQL("""
                    INSERT INTO stream_destinations_new (id, planId, service, title, description, privacyStatus, gameId, tags, rtmpUrl, streamKey, broadcastId, status)
                    SELECT CAST(id AS TEXT), planId, service, title, description, privacyStatus, gameId, tags, rtmpUrl, streamKey, broadcastId, status FROM stream_destinations
                """.trimIndent())
                db.execSQL("DROP TABLE stream_destinations")
                db.execSQL("ALTER TABLE stream_destinations_new RENAME TO stream_destinations")
            }
        }

        val MIGRATION_2_3 = object : Migration(2, 3) {
            override fun migrate(db: SupportSQLiteDatabase) {
                // 1. Rebuild linked_accounts with 'id' as PK instead of 'serviceId'
                db.execSQL("""
                    CREATE TABLE linked_accounts_new (
                        id TEXT NOT NULL PRIMARY KEY,
                        serviceId TEXT NOT NULL,
                        displayName TEXT NOT NULL,
                        accountId TEXT NOT NULL,
                        avatarUrl TEXT
                    )
                """.trimIndent())
                // Migrate existing rows: use accountId as temporary id (will be
                // replaced on next sync from backend)
                db.execSQL("""
                    INSERT INTO linked_accounts_new (id, serviceId, displayName, accountId, avatarUrl)
                    SELECT serviceId || '_' || accountId, serviceId, displayName, accountId, avatarUrl
                    FROM linked_accounts
                """.trimIndent())
                db.execSQL("DROP TABLE linked_accounts")
                db.execSQL("ALTER TABLE linked_accounts_new RENAME TO linked_accounts")

                // 2. Add linkedAccountId column to stream_destinations
                db.execSQL("ALTER TABLE stream_destinations ADD COLUMN linkedAccountId TEXT NOT NULL DEFAULT ''")
            }
        }

        val MIGRATION_3_4 = object : Migration(3, 4) {
            override fun migrate(db: SupportSQLiteDatabase) {
                db.execSQL("ALTER TABLE stream_plans ADD COLUMN executionMode TEXT NOT NULL DEFAULT 'IN_GAME'")
            }
        }

        val MIGRATION_4_5 = object : Migration(4, 5) {
            override fun migrate(db: SupportSQLiteDatabase) {
                db.execSQL("ALTER TABLE linked_accounts ADD COLUMN isEnabled INTEGER NOT NULL DEFAULT 1")
                db.execSQL("ALTER TABLE stream_plans ADD COLUMN gameId TEXT NOT NULL DEFAULT ''")
            }
        }

        val MIGRATION_5_6 = object : Migration(5, 6) {
            override fun migrate(db: SupportSQLiteDatabase) {
                db.execSQL("ALTER TABLE linked_accounts ADD COLUMN rtmpUrl TEXT")
                db.execSQL("ALTER TABLE linked_accounts ADD COLUMN streamKey TEXT")
            }
        }
    }
}
