package com.example.myapplication.database

import android.content.Context
import android.graphics.Bitmap
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import androidx.sqlite.db.SupportSQLiteDatabase
import com.example.myapplication.database.entities.dao.BikeDao
import com.example.myapplication.database.entities.dao.RentDao
import com.example.myapplication.database.entities.dao.RentItemCrossRefDao
import com.example.myapplication.database.entities.dao.ItemDao
import com.example.myapplication.database.entities.dao.UserDao
import com.example.myapplication.database.entities.dao.UserItemCrossRefDao
import com.example.myapplication.database.entities.model.Bike
import com.example.myapplication.database.entities.model.LocalDateTimeConverter
import com.example.myapplication.database.entities.model.Rent
import com.example.myapplication.database.entities.model.RentItemCrossRef
import com.example.myapplication.database.entities.model.Item
import com.example.myapplication.database.entities.model.User
import com.example.myapplication.database.entities.model.UserItemCrossRef
import com.example.myapplication.database.remotekeys.dao.RemoteKeysDao
import com.example.myapplication.database.remotekeys.model.RemoteKeys
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.ByteArrayOutputStream

@Database(
    entities = [
        Bike::class,
        Item::class,
        Rent::class,
        RentItemCrossRef::class,
        User::class,
        UserItemCrossRef::class,
        RemoteKeys::class
    ],
    version = 1,
    exportSchema = false
)
@TypeConverters(LocalDateTimeConverter::class)
abstract class AppDatabase : RoomDatabase() {
    abstract fun bikeDao(): BikeDao
    abstract fun itemDao(): ItemDao
    abstract fun rentDao(): RentDao
    abstract fun rentItemCrossRefDao(): RentItemCrossRefDao
    abstract fun userDao(): UserDao
    abstract fun userItemCrossRefDao(): UserItemCrossRefDao
    abstract fun remoteKeysDao(): RemoteKeysDao

    companion object {
        private const val DB_NAME: String = "pmy-db"

        @Volatile
        private var INSTANCE: AppDatabase? = null

        private suspend fun populateDatabase() {
            INSTANCE?.let { database ->
                // Users
                val userDao = database.userDao()
                val user1 = User(1, "login", "admin", "password")
                userDao.insert(user1)
                /*// Bikes
                val bikeDao = database.bikeDao()
                val bike1 =
                    Bike(1, "a", "Desc1", createColoredImage(android.graphics.Color.BLUE), 2023)
                val bike2 =
                    Bike(2, "b", "Desc2", createColoredImage(android.graphics.Color.GREEN), 2023)
                val bike3 =
                    Bike(3, "c", "Desc3", createColoredImage(android.graphics.Color.RED), 2023)
                val bike4 =
                    Bike(4, "d", "Desc4", createColoredImage(android.graphics.Color.CYAN), 2023)
                bikeDao.insert(bike1)
                bikeDao.insert(bike2)
                bikeDao.insert(bike3)
                bikeDao.insert(bike4)

                for (i in 5..20) {
                    val bike = Bike(
                        uid = i,
                        name = generateBikeName(i),
                        description = "Description $i",
                        image = createColoredImage(getRandomColorInt()),
                    )
                    bikeDao.insert(bike)
                }

                // Rents
                val rentDao = database.rentDao()
                val rent1 = Rent(1, 1)
                val rent2 = Rent(2, 1)
                val rent3 = Rent(3, 1)
                val rent4 = Rent(4, 1)
                rentDao.insert(rent1)
                rentDao.insert(rent2)
                rentDao.insert(rent3)
                rentDao.insert(rent4)
                // Items
                val itemDao = database.itemDao()
                val item1 = Item(1, LocalDateTime.now(), 150.0, 120, bike1.uid)
                val item2 = Item(2, LocalDateTime.now(), 200.0, 110, bike2.uid)
                val item3 = Item(3, LocalDateTime.now(), 300.0, 100, bike3.uid)
                val item4 = Item(4, LocalDateTime.now(), 450.0, 200, bike1.uid)
                itemDao.insert(item1)
                itemDao.insert(item2)
                itemDao.insert(item3)
                itemDao.insert(item4)
                // RentItemCrossRef для связи арендаов с сеансами
                val rentItemCrossRefDao = database.rentItemCrossRefDao()
                if (item1.uid != null && item2.uid != null && item3.uid != null) {
                    val rentItemCrossRef1 =
                        RentItemCrossRef(rent1.uid, item3.uid, 150.0, 5)
                    val rentItemCrossRef2 =
                        RentItemCrossRef(rent1.uid, item2.uid, 300.0, 10)
                    val rentItemCrossRef3 =
                        RentItemCrossRef(rent2.uid, item2.uid, 350.0, 6)
                    val rentItemCrossRef4 =
                        RentItemCrossRef(rent3.uid, item1.uid, 250.0, 10)
                    val rentItemCrossRef5 =
                        RentItemCrossRef(rent3.uid, item3.uid, 150.0, 16)
                    val rentItemCrossRef6 =
                        RentItemCrossRef(rent4.uid, item3.uid, 150.0, 2)
                    rentItemCrossRefDao.insert(rentItemCrossRef1)
                    rentItemCrossRefDao.insert(rentItemCrossRef2)
                    rentItemCrossRefDao.insert(rentItemCrossRef3)
                    rentItemCrossRefDao.insert(rentItemCrossRef4)
                    rentItemCrossRefDao.insert(rentItemCrossRef5)
                    rentItemCrossRefDao.insert(rentItemCrossRef6)
                }
                // UserItems
                val userItemCrossRefDao = database.userItemCrossRefDao()
                val userItemCrossRef1 = UserItemCrossRef(1, 1, 5)
                val userItemCrossRef2 = UserItemCrossRef(1, 3, 15)
                userItemCrossRefDao.insert(userItemCrossRef1)
                userItemCrossRefDao.insert(userItemCrossRef2)*/
            }
        }

        fun getInstance(appContext: Context): AppDatabase {
            return INSTANCE ?: synchronized(this) {
                Room.databaseBuilder(
                    appContext,
                    AppDatabase::class.java,
                    DB_NAME
                )
                    .addCallback(object : Callback() {
                        override fun onCreate(db: SupportSQLiteDatabase) {
                            super.onCreate(db)
                            CoroutineScope(Dispatchers.IO).launch {
                                populateDatabase()
                            }
                        }
                    })
                    .build()
                    .also { INSTANCE = it }
            }
        }

        private fun createColoredImage(color: Int): ByteArray {
            val width = 100
            val height = 100

            val bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
            bmp.eraseColor(color)

            val stream = ByteArrayOutputStream()
            bmp.compress(Bitmap.CompressFormat.PNG, 100, stream)

            return stream.toByteArray()
        }

        private fun getRandomColorInt(): Int {
            val red = (0..255).random()
            val green = (0..255).random()
            val blue = (0..255).random()
            return (0xFF shl 24) or (red shl 16) or (green shl 8) or blue
        }

        private fun generateBikeName(index: Int): String {
            val base = 'a'.code
            val alphabetSize = 26
            val sb = StringBuilder()
            var remainder = index
            do {
                val letter = (remainder % alphabetSize + base).toChar()
                sb.insert(0, letter)
                remainder /= alphabetSize
            } while (remainder > 0)
            return sb.toString()
        }
    }
}