package com.rosetta.messenger.database

import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase

@Database(
        entities =
                [
                        EncryptedAccountEntity::class,
                        MessageEntity::class,
                        MessageSearchIndexEntity::class,
                        DialogEntity::class,
                        BlacklistEntity::class,
                        AvatarCacheEntity::class,
                        AccountSyncTimeEntity::class,
                        GroupEntity::class,
                        PinnedMessageEntity::class],
        version = 17,
        exportSchema = false
)
abstract class RosettaDatabase : RoomDatabase() {
    abstract fun accountDao(): AccountDao
    abstract fun messageDao(): MessageDao
    abstract fun dialogDao(): DialogDao
    abstract fun blacklistDao(): BlacklistDao
    abstract fun avatarDao(): AvatarDao
    abstract fun syncTimeDao(): SyncTimeDao
    abstract fun groupDao(): GroupDao
    abstract fun pinnedMessageDao(): PinnedMessageDao
    abstract fun messageSearchIndexDao(): MessageSearchIndexDao

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

        private val MIGRATION_4_5 =
                object : Migration(4, 5) {
                    override fun migrate(database: SupportSQLiteDatabase) {
                        // Добавляем новые столбцы для индикаторов прочтения
                        database.execSQL(
                                "ALTER TABLE dialogs ADD COLUMN last_message_from_me INTEGER NOT NULL DEFAULT 0"
                        )
                        database.execSQL(
                                "ALTER TABLE dialogs ADD COLUMN last_message_delivered INTEGER NOT NULL DEFAULT 0"
                        )
                        database.execSQL(
                                "ALTER TABLE dialogs ADD COLUMN last_message_read INTEGER NOT NULL DEFAULT 0"
                        )
                    }
                }

        private val MIGRATION_5_6 =
                object : Migration(5, 6) {
                    override fun migrate(database: SupportSQLiteDatabase) {
                        // Добавляем поле username в encrypted_accounts
                        database.execSQL("ALTER TABLE encrypted_accounts ADD COLUMN username TEXT")
                    }
                }

        private val MIGRATION_6_7 =
                object : Migration(6, 7) {
                    override fun migrate(database: SupportSQLiteDatabase) {
                        // Создаем таблицу для кэша аватаров
                        database.execSQL(
                                """
                    CREATE TABLE IF NOT EXISTS avatar_cache (
                        id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
                        public_key TEXT NOT NULL,
                        avatar TEXT NOT NULL,
                        timestamp INTEGER NOT NULL
                    )
                """
                        )
                        database.execSQL(
                                "CREATE INDEX IF NOT EXISTS index_avatar_cache_public_key_timestamp ON avatar_cache (public_key, timestamp)"
                        )
                    }
                }

        private val MIGRATION_7_8 =
                object : Migration(7, 8) {
                    override fun migrate(database: SupportSQLiteDatabase) {
                        // Удаляем таблицу avatar_delivery (больше не нужна)
                        database.execSQL("DROP TABLE IF EXISTS avatar_delivery")
                    }
                }

        /**
         * 🔥 МИГРАЦИЯ 8->9: Очищаем blob из attachments (как в desktop) Blob слишком большой для
         * SQLite CursorWindow (2MB лимит) Просто обнуляем attachments - изображения перескачаются с
         * CDN
         */
        private val MIGRATION_8_9 =
                object : Migration(8, 9) {
                    override fun migrate(database: SupportSQLiteDatabase) {
                        // Очищаем все attachments с большими blob'ами
                        // Они будут перескачаны с CDN при открытии
                        database.execSQL(
                                """
                    UPDATE messages 
                    SET attachments = '[]'
                    WHERE length(attachments) > 10000
                """
                        )
                    }
                }

        /**
         * 🔥 МИГРАЦИЯ 9->10: Повторная очистка blob из attachments Для пользователей которые уже
         * были на версии 9
         */
        private val MIGRATION_9_10 =
                object : Migration(9, 10) {
                    override fun migrate(database: SupportSQLiteDatabase) {
                        // Очищаем все attachments с большими blob'ами
                        database.execSQL(
                                """
                    UPDATE messages 
                    SET attachments = '[]'
                    WHERE length(attachments) > 10000
                """
                        )
                    }
                }

        /**
         * 🚀 МИГРАЦИЯ 10->11: Денормализация — кэш attachments последнего сообщения в dialogs
         * Устраняет N+1 проблему: ранее для каждого диалога делался отдельный запрос к messages
         */
        private val MIGRATION_10_11 =
                object : Migration(10, 11) {
                    override fun migrate(database: SupportSQLiteDatabase) {
                        // Добавляем столбец для кэша attachments последнего сообщения
                        database.execSQL(
                                "ALTER TABLE dialogs ADD COLUMN last_message_attachments TEXT NOT NULL DEFAULT '[]'"
                        )
                    }
                }

        private val MIGRATION_11_12 =
                object : Migration(11, 12) {
                    override fun migrate(database: SupportSQLiteDatabase) {
                        database.execSQL(
                                """
                    CREATE TABLE IF NOT EXISTS accounts_sync_times (
                        account TEXT NOT NULL PRIMARY KEY,
                        last_sync INTEGER NOT NULL
                    )
                """
                        )
                    }
                }

        /**
         * 📌 МИГРАЦИЯ 12->13: Таблица pinned_messages для закреплённых сообщений (Telegram-style)
         */
        private val MIGRATION_12_13 =
                object : Migration(12, 13) {
                    override fun migrate(database: SupportSQLiteDatabase) {
                        database.execSQL(
                                """
                    CREATE TABLE IF NOT EXISTS pinned_messages (
                        id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
                        account TEXT NOT NULL,
                        dialog_key TEXT NOT NULL,
                        message_id TEXT NOT NULL,
                        pinned_at INTEGER NOT NULL
                    )
                """
                        )
                        database.execSQL(
                                "CREATE UNIQUE INDEX IF NOT EXISTS index_pinned_messages_account_dialog_key_message_id ON pinned_messages (account, dialog_key, message_id)"
                        )
                        database.execSQL(
                                "CREATE INDEX IF NOT EXISTS index_pinned_messages_account_dialog_key_pinned_at ON pinned_messages (account, dialog_key, pinned_at)"
                        )
                    }
                }

        /**
         * 👥 МИГРАЦИЯ 13->14: Таблица groups для групповых диалогов
         */
        private val MIGRATION_13_14 =
                object : Migration(13, 14) {
                    override fun migrate(database: SupportSQLiteDatabase) {
                        database.execSQL(
                                """
                    CREATE TABLE IF NOT EXISTS groups (
                        id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
                        account TEXT NOT NULL,
                        group_id TEXT NOT NULL,
                        title TEXT NOT NULL,
                        description TEXT NOT NULL,
                        `key` TEXT NOT NULL
                    )
                """
                        )
                        database.execSQL(
                                "CREATE UNIQUE INDEX IF NOT EXISTS index_groups_account_group_id ON groups (account, group_id)"
                        )
                    }
                }

        /**
         * 🧱 МИГРАЦИЯ 14->15: Денормализованный тип вложения для ускорения фильтров (media/files/calls)
         */
        private val MIGRATION_14_15 =
                object : Migration(14, 15) {
                    override fun migrate(database: SupportSQLiteDatabase) {
                        database.execSQL(
                                "ALTER TABLE messages ADD COLUMN primary_attachment_type INTEGER NOT NULL DEFAULT -1"
                        )
                        database.execSQL(
                                "CREATE INDEX IF NOT EXISTS index_messages_account_primary_attachment_type_timestamp ON messages (account, primary_attachment_type, timestamp)"
                        )
                        // Best-effort backfill для уже сохраненных сообщений.
                        database.execSQL(
                                """
                    UPDATE messages
                    SET primary_attachment_type = CASE
                        WHEN attachments IS NULL OR TRIM(attachments) = '' OR TRIM(attachments) = '[]' THEN -1
                        WHEN attachments LIKE '%"type":0%' OR attachments LIKE '%"type": 0%' THEN 0
                        WHEN attachments LIKE '%"type":1%' OR attachments LIKE '%"type": 1%' THEN 1
                        WHEN attachments LIKE '%"type":2%' OR attachments LIKE '%"type": 2%' THEN 2
                        WHEN attachments LIKE '%"type":3%' OR attachments LIKE '%"type": 3%' THEN 3
                        WHEN attachments LIKE '%"type":4%' OR attachments LIKE '%"type": 4%' THEN 4
                        ELSE -1
                    END
                """
                        )
                    }
                }

        /**
         * 🧱 МИГРАЦИЯ 15->16: Денормализованный has_content для быстрых выборок dialogs/requests
         */
        private val MIGRATION_15_16 =
                object : Migration(15, 16) {
                    override fun migrate(database: SupportSQLiteDatabase) {
                        database.execSQL(
                                "ALTER TABLE dialogs ADD COLUMN has_content INTEGER NOT NULL DEFAULT 0"
                        )
                        database.execSQL(
                                "CREATE INDEX IF NOT EXISTS index_dialogs_account_i_have_sent_has_content_last_message_timestamp ON dialogs (account, i_have_sent, has_content, last_message_timestamp)"
                        )
                        database.execSQL(
                                """
                    UPDATE dialogs
                    SET has_content = CASE
                        WHEN TRIM(last_message) != '' THEN 1
                        WHEN last_message_attachments IS NOT NULL
                             AND TRIM(last_message_attachments) != ''
                             AND TRIM(last_message_attachments) != '[]' THEN 1
                        ELSE 0
                    END
                """
                        )
                    }
                }

        /**
         * 🧱 МИГРАЦИЯ 16->17:
         * - dialogs: last_message_attachment_type + last_sender_key
         * - messages: индекс (account, timestamp)
         * - локальный message_search_index для поиска без повторной дешифровки
         */
        private val MIGRATION_16_17 =
                object : Migration(16, 17) {
                    override fun migrate(database: SupportSQLiteDatabase) {
                        database.execSQL(
                                "ALTER TABLE dialogs ADD COLUMN last_message_attachment_type INTEGER NOT NULL DEFAULT -1"
                        )
                        database.execSQL(
                                "ALTER TABLE dialogs ADD COLUMN last_sender_key TEXT NOT NULL DEFAULT ''"
                        )
                        database.execSQL(
                                "CREATE INDEX IF NOT EXISTS index_messages_account_timestamp ON messages (account, timestamp)"
                        )
                        database.execSQL(
                                """
                    CREATE TABLE IF NOT EXISTS message_search_index (
                        account TEXT NOT NULL,
                        message_id TEXT NOT NULL,
                        dialog_key TEXT NOT NULL,
                        opponent_key TEXT NOT NULL,
                        timestamp INTEGER NOT NULL,
                        from_me INTEGER NOT NULL DEFAULT 0,
                        plain_text TEXT NOT NULL,
                        plain_text_normalized TEXT NOT NULL,
                        PRIMARY KEY(account, message_id)
                    )
                """
                        )
                        database.execSQL(
                                "CREATE INDEX IF NOT EXISTS index_message_search_index_account_timestamp ON message_search_index (account, timestamp)"
                        )
                        database.execSQL(
                                "CREATE INDEX IF NOT EXISTS index_message_search_index_account_opponent_key_timestamp ON message_search_index (account, opponent_key, timestamp)"
                        )
                        database.execSQL(
                                """
                    UPDATE dialogs
                    SET last_message_attachment_type = CASE
                        WHEN last_message_attachments IS NULL
                             OR TRIM(last_message_attachments) = ''
                             OR TRIM(last_message_attachments) = '[]' THEN -1
                        WHEN last_message_attachments LIKE '%"type":0%' OR last_message_attachments LIKE '%"type": 0%' THEN 0
                        WHEN last_message_attachments LIKE '%"type":1%' OR last_message_attachments LIKE '%"type": 1%' THEN 1
                        WHEN last_message_attachments LIKE '%"type":2%' OR last_message_attachments LIKE '%"type": 2%' THEN 2
                        WHEN last_message_attachments LIKE '%"type":3%' OR last_message_attachments LIKE '%"type": 3%' THEN 3
                        WHEN last_message_attachments LIKE '%"type":4%' OR last_message_attachments LIKE '%"type": 4%' THEN 4
                        ELSE -1
                    END
                """
                        )
                        database.execSQL(
                                """
                    UPDATE dialogs
                    SET last_sender_key = COALESCE(
                        (
                            SELECT m.from_public_key
                            FROM messages m
                            WHERE m.account = dialogs.account
                              AND m.dialog_key = CASE
                                    WHEN dialogs.opponent_key = dialogs.account THEN dialogs.account
                                    WHEN LOWER(dialogs.opponent_key) LIKE '#group:%' OR LOWER(dialogs.opponent_key) LIKE 'group:%'
                                        THEN dialogs.opponent_key
                                    WHEN dialogs.account < dialogs.opponent_key
                                        THEN dialogs.account || ':' || dialogs.opponent_key
                                    ELSE dialogs.opponent_key || ':' || dialogs.account
                                END
                            ORDER BY m.timestamp DESC, m.id DESC
                            LIMIT 1
                        ),
                        ''
                    )
                """
                        )
                        database.execSQL(
                                """
                    CREATE TRIGGER IF NOT EXISTS trg_message_search_index_delete
                    AFTER DELETE ON messages
                    BEGIN
                        DELETE FROM message_search_index
                        WHERE account = OLD.account AND message_id = OLD.message_id;
                    END
                """
                        )
                    }
                }

        fun getDatabase(context: Context): RosettaDatabase {
            return INSTANCE
                    ?: synchronized(this) {
                        val instance =
                                Room.databaseBuilder(
                                                context.applicationContext,
                                                RosettaDatabase::class.java,
                                                "rosetta_secure.db"
                                        )
                                        .setJournalMode(
                                                JournalMode.WRITE_AHEAD_LOGGING
                                        ) // WAL mode for performance
                                        .addMigrations(
                                                MIGRATION_4_5,
                                                MIGRATION_5_6,
                                                MIGRATION_6_7,
                                                MIGRATION_7_8,
                                                MIGRATION_8_9,
                                                MIGRATION_9_10,
                                                MIGRATION_10_11,
                                                MIGRATION_11_12,
                                                MIGRATION_12_13,
                                                MIGRATION_13_14,
                                                MIGRATION_14_15,
                                                MIGRATION_15_16,
                                                MIGRATION_16_17
                                        )
                                        .fallbackToDestructiveMigration() // Для разработки - только
                                        // если миграция не
                                        // найдена
                                        .build()
                        INSTANCE = instance
                        instance
                    }
        }
    }
}
