@file:Suppress("HardCodedStringLiteral", "unused")

package eu.gaudian.translator.model.repository

import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import eu.gaudian.translator.model.communication.FileInfo
import eu.gaudian.translator.utils.Log

/**
 * Repository for generic access and reading of downloaded dictionary .db files.
 * All operations are read-only. The .db files are assumed to be SQLite databases.
 */
class DictionaryDatabaseRepository(private val context: Context) {

    @Suppress("PrivatePropertyName")
    private val TAG = "DictionaryDatabaseRepository"

    /**
     * Opens a read-only SQLite database for the given file info.
     * Returns null if the file does not exist.
     */
    internal fun getDatabase(fileInfo: FileInfo): SQLiteDatabase? {
        val dbAsset = fileInfo.assets.firstOrNull { it.filename.endsWith(".db") }
        if (dbAsset == null) {
            Log.e(TAG, "No database asset found for ${fileInfo.id}")
            return null
        }

        val file = java.io.File(context.filesDir, dbAsset.filename)
        return if (file.exists()) {
            try {
                // Use URI mode with immutable=1 to reduce locking noise
                val path = "file:${file.absolutePath}?mode=ro&immutable=1"
                SQLiteDatabase.openDatabase(
                    path,
                    null,
                    SQLiteDatabase.OPEN_READONLY
                )
            } catch (e: Exception) {
                Log.e(TAG, "Error opening database for ${dbAsset.filename}", e)
                null
            }
        } else {
            Log.w(TAG, "Database file does not exist: ${dbAsset.filename}")
            null
        }
    }

    /**
     * Retrieves the list of table names in the database.
     */
    fun getTables(fileInfo: FileInfo): List<String> {
        val db = getDatabase(fileInfo) ?: return emptyList()
        val tables = mutableListOf<String>()
        db.rawQuery("SELECT name FROM sqlite_master WHERE type='table'", null).use { cursor ->
            while (cursor.moveToNext()) {
                tables.add(cursor.getString(0))
            }
        }
        db.close()
        return tables
    }

    /**
     * Retrieves the list of column names for a specific table.
     */
    fun getColumns(fileInfo: FileInfo, table: String): List<String> {
        val db = getDatabase(fileInfo) ?: return emptyList()
        val columns = mutableListOf<String>()
        db.rawQuery("PRAGMA table_info($table)", null).use { cursor ->
            while (cursor.moveToNext()) {
                columns.add(cursor.getString(1)) // name column index is 1
            }
        }
        db.close()
        return columns
    }

    /**
     * Retrieves up to [limit] rows from a table as a list of maps (column name to value).
     * Defaults to first 1000 rows if limit is not specified.
     */
    fun getTableData(fileInfo: FileInfo, table: String, limit: Int = 1000): List<Map<String, Any>> {
        val db = getDatabase(fileInfo) ?: return emptyList()
        val data = mutableListOf<Map<String, Any>>()
        db.rawQuery("SELECT * FROM $table LIMIT $limit", null).use { cursor ->
            val columnCount = cursor.columnCount
            val columnNames = Array(columnCount) { i -> cursor.getColumnName(i) }
            while (cursor.moveToNext()) {
                val row = mutableMapOf<String, Any>()
                for (i in 0 until columnCount) {
                    val name = columnNames[i]
                    val value = when (cursor.getType(i)) {
                        Cursor.FIELD_TYPE_INTEGER -> cursor.getLong(i)
                        Cursor.FIELD_TYPE_FLOAT -> cursor.getDouble(i)
                        Cursor.FIELD_TYPE_STRING -> cursor.getString(i)
                        Cursor.FIELD_TYPE_BLOB -> "BLOB (${cursor.getBlob(i)?.size ?: 0} bytes)"
                        else -> null
                    }
                    value?.let { row[name] = it }
                }
                data.add(row)
            }
        }
        db.close()
        return data
    }

    /**
     * Checks if a table exists in the database.
     */
    fun tableExists(fileInfo: FileInfo, table: String): Boolean {
        val db = getDatabase(fileInfo) ?: return false
        val exists = db.rawQuery("SELECT name FROM sqlite_master WHERE type='table' AND name='$table'", null).use { cursor ->
            cursor.moveToFirst()
        }
        db.close()
        return exists
    }

    /**
     * Gets the row count for a specific table.
     */
    fun getRowCount(fileInfo: FileInfo, table: String): Int {
        val db = getDatabase(fileInfo) ?: return 0
        var count = 0
        db.rawQuery("SELECT COUNT(*) FROM $table", null).use { cursor ->
            if (cursor.moveToFirst()) {
                count = cursor.getInt(0)
            }
        }
        db.close()
        return count
    }
}