package es.verdnatura.db

import android.content.Context
import androidx.room.*
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import es.verdnatura.presentation.view.feature.delivery.model.ClientTicketSalix
import es.verdnatura.presentation.view.feature.delivery.model.ExpeditionInfoLoadUnload
import es.verdnatura.presentation.view.feature.delivery.model.ExpeditionInfoPending
import es.verdnatura.presentation.view.feature.delivery.model.MyLocation
import es.verdnatura.presentation.view.feature.delivery.model.RouteInfo
import es.verdnatura.presentation.view.feature.delivery.model.RouteLoaded
import es.verdnatura.presentation.view.feature.delivery.model.SignedTickets
import es.verdnatura.presentation.view.feature.delivery.model.Ticket
import java.util.Date

// Clase que representa la base de datos
@Database(
    entities = [ExpeditionInfoLoadUnload::class, ExpeditionInfoPending::class, SignedTickets::class, RouteInfo::class, ClientTicketSalix::class, RouteLoaded::class],
    version = 1,
    exportSchema = false

)
@TypeConverters(MapTypeConverter::class)
abstract class DeliveryDatabase : RoomDatabase() {
    abstract fun expedicionDao(): ExpedicionDao
    abstract fun signedTicketDao(): SignedTicketDao
    abstract fun routesDao(): RoutesDao

    abstract fun clienTicketDao(): ClientTicketDao

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

        fun getInstance(context: Context): DeliveryDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext, DeliveryDatabase::class.java, "expedition_database"
                ).fallbackToDestructiveMigration().build()
                INSTANCE = instance
                instance
            }
        }
    }
}

// Interfaz que define los métodos de acceso a datos para Expedicion
@Dao
interface ExpedicionDao {
    @Query("SELECT * FROM expedition e WHERE e.routeFk = :parametro1")
    suspend fun getAll(parametro1: Int): MutableList<ExpeditionInfoLoadUnload>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(expedition: MutableList<ExpeditionInfoLoadUnload>)

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertPending(expeditionPending: MutableList<ExpeditionInfoPending>)

    @Query("SELECT * FROM expeditionPending ep WHERE ep.routeFk=:routeFk")
    suspend fun getAllPending(routeFk: Int): MutableList<ExpeditionInfoLoadUnload>

    @Query("SELECT * FROM expeditionPending")
    suspend fun getAllPendingExpeditions(): MutableList<ExpeditionInfoPending>

    @Delete
    fun delete(expedition: ExpeditionInfoLoadUnload)

    @Query("DELETE  FROM expeditionPending WHERE code = :codeState")
    suspend fun getDeleteByState(codeState: String)
}

@Dao
interface SignedTicketDao {
    @Query("SELECT * FROM signedPending ")
    suspend fun getAll(): List<SignedTickets>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(signedTicketPending: SignedTickets)

    @Query("DELETE FROM signedPending WHERE fileName = :nameFile")
    fun deleteByNameFile(nameFile: String)
}

@Dao
interface RoutesDao {
    @Query("SELECT * FROM routes ")
    suspend fun getAll(): List<RouteInfo>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(routes: List<RouteInfo>)

    @Query("DELETE FROM routes ")
    suspend fun delete()

    @Query("DELETE FROM routes WHERE id = :routeId")
    suspend fun deleteByNameFile(routeId: String)

    @Query("SELECT * FROM routesLoaded ")
    suspend fun getAllLoaded(): List<RouteLoaded>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertLoaded(routeLoaded: RouteLoaded)

    @Query("DELETE FROM routes WHERE  created != :today")
    suspend fun deleteLoaded(today: String)

}

@Dao
interface ClientTicketDao {
    @Query("SELECT * FROM clientTickets ")
    suspend fun getAll(): List<ClientTicketSalix>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(routes: List<ClientTicketSalix>)

    @Query("DELETE FROM clientTickets ")
    suspend fun delete()

    @Query("DELETE FROM clientTickets WHERE id = :ticketId")
    suspend fun deleteById(ticketId: Int)

}

class MapTypeConverter {
    private val gson = Gson()

    @TypeConverter
    fun fromMap(map: Map<String, String>): String {
        return gson.toJson(map)
    }

    @TypeConverter
    fun toMap(json: String): Map<String, String> {
        val type = object : TypeToken<Map<String, String>>() {}.type
        return gson.fromJson(json, type)
    }

    @TypeConverter
    fun fromDate(date: Date): Long {
        return date.time
    }

    @TypeConverter
    fun toDate(timestamp: Long): Date {
        return Date(timestamp)
    }

    @TypeConverter
    fun fromMyLocation(location: MyLocation?): String? {
        return gson.toJson(location)
    }

    @TypeConverter
    fun toMyLocation(json: String?): MyLocation? {
        val type = object : TypeToken<MyLocation>() {}.type
        return gson.fromJson(json, type)
    }

    @TypeConverter
    fun fromPhones(phones: List<String>): String {
        return gson.toJson(phones)
    }

    @TypeConverter
    fun toPhones(json: String): List<String> {
        val type = object : TypeToken<List<String>>() {}.type
        return gson.fromJson(json, type)
    }

    @TypeConverter
    fun fromTickets(tickets: MutableList<Ticket?>): String? {
        return gson.toJson(tickets)
    }

    @TypeConverter
    fun toTickets(json: String?): MutableList<Ticket?> {
        val type = object : TypeToken<MutableList<Ticket>>() {}.type
        return gson.fromJson(json, type)
    }
}