package com.example.rehabilitation.db

import android.annotation.SuppressLint
import android.content.ContentValues
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.provider.BaseColumns
import com.example.rehabilitation.db.MyDbHelper
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

//Для работы с базой данных(запись, считывание и вывод)
class MyDbManeger(contex: Context) {//(contex: Context) - контекс потому что наш MyDbHelper ждет контекста, и когда мы запустим MyDbHelper, то мы через contex и передадим в него его contex

    val myDbHelper = MyDbHelper(contex)//Вот мы и передали контекст в MyDbHelper и сделали для него отдельную переменную
    var db: SQLiteDatabase? = null//Через этот объект мы будем открввать и записывать данные в базу данных

    fun openDB(){//Открытие
        db = myDbHelper.writableDatabase//writableDatabase - база откылась для записей
    }

    fun closeDB(){//Закрытие
        myDbHelper.close()//close() - база закрылась для записей
    }

    //Обновление данных
   suspend fun updateItemDB(title: String, content:String,uri:String, id: Int, time:String) = withContext(Dispatchers.IO){//Обновление по id//Функция для обновленяи записей//title: String, content:String - 1 и 2 клонка
        val selection = BaseColumns._ID + "=$id"//Индификатор по которому будем определять что обновлять
        val valuess = ContentValues().apply {//ContentValues() - что-то типа массива или хэш-мап, где сохраняется в виде ключа наши значения//Тут мы созадлем ключи для более удобной связи с передаваемыми даннымми в колонку, а также чтобы сделать ключь для колонки
            put(MyDbNameClass.COLUMN_NAME_TITLE, title)//1 колонка
            put(MyDbNameClass.COLUMN_NAME_CONTENT, content)//2 колонка
            put(MyDbNameClass.COLUMN_NAME_IMAGE_URI, uri)//3 колонка
            put(MyDbNameClass.COLUMN_NAME_TIME, time)//4 колонка//Обновляем время после каждого пересохранения
        }
        db?.update(MyDbNameClass.TABLE_NAME,valuess,selection,null)//Обновление данных//1 - где хоти обновть(название таблицы), 2 - что хотим обноновить в данно м элементе, 3 - selction
    }



    //Вставлять или добавлять данные
    suspend fun insertToDB   (title: String, content:String,uri:String, time: String)= withContext(Dispatchers.IO){//Запись//Функция для записей в базу данных, что бы создавать(отправлять) записи//title: String, content:String - 1 и 2 клонка
        val valuess = ContentValues().apply {//ContentValues() - что-то типа массива или хэш-мап, где сохраняется в виде ключа наши значения//Тут мы созадлем ключи для более удобной связи с передаваемыми даннымми в колонку, а также чтобы сделать ключь для колонки
            put(MyDbNameClass.COLUMN_NAME_TITLE, title)//1 колонка
            put(MyDbNameClass.COLUMN_NAME_CONTENT, content)//2 колонка
            put(MyDbNameClass.COLUMN_NAME_IMAGE_URI, uri)//3 колонка
            put(MyDbNameClass.COLUMN_NAME_TIME, time)//4 колонка
        }
        db?.insert(MyDbNameClass.TABLE_NAME,null,valuess)//Передача в базу
    }

    //Удаление
    fun removeItemDeleteFromDB(id: String){//Функция удаления по свайпу, удаление рпоисходит по id так как названия могут совпадать, а id нет
        val selection = BaseColumns._ID + "=$id"//Удадаляем по индификатору, где индификатор равен моему индификатору - / + "=$id" /
        db?.delete(MyDbNameClass.TABLE_NAME,selection, null)//Удаление из базы//MyDbNameClass.TABLE_NAME - из какой таблицы
    }

    //Считывание
    @SuppressLint("Range")//suspend fun - эта функция будет блокировать Coroutine пока не завиршится, то есть теперь основной поток не будит блокироваться для обновления данных, а данные обновятся на второстепенном потоке, что бы не блокировать основные действия из-за прогрузки, а уже когда полностью загрузятся на второстепенном потоке, то они заблакирую основно поток и выведут данные и никакгого дискамфорта не будет от того что виснет от прогрузки что-то, то есть пока все не прогрузится на второстепенном потоке ничего лмшний раз блокировать основной поток не будет и программа будет работать без перебоее, а же когда загрузятся данные из базы данных, то основной поток займется для обновления данных// = withContext(Dispatchers.IO) - запускает эту функцию там где я укажу, то есть я укажу на второстепенном потоке //IO - второстепенный поток
    suspend fun readDBData(searchText:String) : ArrayList<ListItem> = withContext(Dispatchers.IO){//Для считывания//ArrayList<ListItem> - будет возвращать массив в который будет записанно все, что будет в базе данных//ArrayList<ListItem> - тип данных котоорый мы ждем при чтение
        val dataList = ArrayList<ListItem>()//Массив для данных//Кторы мы и перпедадим readDBData()
        val selectionKolon = "${MyDbNameClass.COLUMN_NAME_TITLE} like ?"//То по какой колонке мы будим искать// like ? - это для запросов к базе
        val cursor = db?.query(//Считывание данных, тут их можно сортировать, отслежывать и братьт определенные за счет всех этих параметров//После того как заполнили наш dataList, то cursor нужно отключть, чтобы не потреблять лишние данные
            MyDbNameClass.TABLE_NAME,   // The table to query
            null,             // The array of columns to return (pass null to get all)
            selectionKolon,//Колонка по которой мы в базе данных будем искать // The columns for the WHERE clause
            arrayOf("%$searchText%"),// arrayOf(searchText)- передаем в таком виде(в виде массива) так как мы не можем прост передат переменную с текстом//"%$searchText%" - ишим по любому совпадению// The values for the WHERE clause
            null,                   // don't group the rows
            null,                   // don't filter by row groups
            null               // The sort order
        )

    //СЧИТЫВАНИЕ ДАННЫХ
    /*1 вариант
      with(cursor){// with(cursor) - чтобы получить доступ к функциям нашего класса, не указывая cursor.moveToNext(), и теперь то что записанно в  with(cursor) это и будит наш cursor
           while (this?.moveToNext()!!){//!! - что бы небыл на cursor null, для того чтобы причсчитывание он остановылися когда закончились элементы в массиве, то есть считывает пока не придет к концу базы и придя к концу выходит из функции
               val dataText = cursor?.getString(cursor.getColumnIndex(MyDbNameClass.COLUMN_NAME_TITLE))//.getColumnIndex() - номер строки
               dataList.add(dataText.toString())
           }
       }*/

    //СЧИТЫВАНИЕ ДАННЫХ
        /*2 вариант*/
           while (cursor?.moveToNext()!!){//!! - что бы небыл на cursor null, для того чтобы при считывание он остановылися когда закончились элементы в массиве, то есть считывает пока не придет к концу базы и придя к концу выходит из функции
               val dataTitle = cursor.getString(cursor.getColumnIndex(MyDbNameClass.COLUMN_NAME_TITLE))//.getColumnIndex() - номер строки//То что мы считываем
               val dataContent = cursor.getString(cursor.getColumnIndex(MyDbNameClass.COLUMN_NAME_CONTENT))
               val dataUri = cursor.getString(cursor.getColumnIndex(MyDbNameClass.COLUMN_NAME_IMAGE_URI))
               val dataId = cursor.getInt(cursor.getColumnIndex(BaseColumns._ID))
               val dataTime = cursor.getString(cursor.getColumnIndex(MyDbNameClass.COLUMN_NAME_TIME))



               //val dataText2 = cursor.getString(cursor.getColumnIndex(MyDbNameClass.COLUMN_NAME_CONTENT))//.getColumnIndex() - номер строки
               val item = ListItem()//Для связи с нашим класс в который мы и передаем данные
               item.id = dataId//Передаем id
               item.title = dataTitle//Передаем название
               item.desc = dataContent//Передаем описание
               item.uri = dataUri//Передаем фотографию
               item.time = dataTime//Передаем время
               dataList.add(item)//Передаем item со всеми данными
           }

        cursor.close()//Закрыли курсор так как закончили с ним работать

       return@withContext dataList//@withContext - так как мы используем @withContext в функции для считывания, а она возврошает лист, то просто так его не примит и нужно указать @withContext для правильной работы
   }



}






























