package dominando.android.data_fb

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import androidx.lifecycle.LiveData
import com.google.android.gms.tasks.Task
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.firestore.*
import com.google.firebase.storage.FirebaseStorage
import dominando.android.data.BooksRepository
import dominando.android.data.model.Book
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream

class FbRepository : BooksRepository {
    private val fbAuth = FirebaseAuth.getInstance()
    private val firestore = FirebaseFirestore.getInstance()
    private val storageRef = FirebaseStorage.getInstance().reference.child(BOOKS_KEY)

    override fun saveBook(book: Book): LiveData<Boolean> {
        return object : LiveData<Boolean>() {
            var inProgress = false
            val currentUser = fbAuth.currentUser
            override fun onActive() {
                super.onActive()
                if (inProgress) {
                    return
                }
                inProgress = true
                if (currentUser == null) {
                    throw SecurityException("Invalid user")
                }
                val db = firestore
                val collection = db.collection(BOOKS_KEY)
                val saveTask = if (book.id.isBlank()) {
                    collection.add(book)
                            .addOnSuccessListener { doc ->
                                book.id = doc.id
                                doc.update(mapOf(USER_ID_KEY to currentUser.uid, ID_KEY to book.id))
                            }

                } else {
                    collection.document(book.id)
                            .set(book, SetOptions.merge())
                }
                saveTask.continueWith { task ->
                    if (task.isSuccessful) {
                        if (book.coverUrl.startsWith("file://")) {
                            uploadFile()
                        } else {
                            value = true
                        }
                    } else {
                        value = false
                    }
                }
            }
            fun uploadFile() {
                uploadPhoto(book).continueWithTask { urlTask ->
                    File(book.coverUrl).delete()
                    book.coverUrl = urlTask.result.toString()
                    firestore.collection(BOOKS_KEY)
                            .document(book.id)
                            .update(COVER_URL_KEY, book.coverUrl)
                }.addOnCompleteListener { task ->
                    value = task.isSuccessful
                }
            }
        }
    }

    override fun loadBooks(): LiveData<List<Book>> {
        return object : LiveData<List<Book>>() {
            val currentUser = fbAuth.currentUser
            val query = firestore.collection(BOOKS_KEY)
                    .whereEqualTo(USER_ID_KEY, currentUser?.uid)

            val listener = EventListener<QuerySnapshot> { snapshot, e ->
                if (e == null) {
                    val books = snapshot?.map { document ->
                        document.toObject(Book::class.java)
                    }
                    value = books
                } else {
                    throw e
                }
            }

            override fun onActive() {
                super.onActive()
                query.addSnapshotListener(listener)
            }
        }
    }

    override fun loadBook(bookId: String): LiveData<Book> {
        return object : LiveData<Book>() {
            override fun onActive() {
                super.onActive()
                val query = firestore.collection(BOOKS_KEY).document(bookId)
                val listener = EventListener<DocumentSnapshot> { snapshot, e ->
                    if (e == null) {
                        value = snapshot?.toObject(Book::class.java)
                    } else {
                        throw e
                    }
                }
                query.addSnapshotListener(listener)
            }
        }
    }

    override fun remove(book: Book): LiveData<Boolean> {
        return object : LiveData<Boolean>() {
            override fun onActive() {
                super.onActive()
                val db = firestore
                db.collection(BOOKS_KEY)
                        .document(book.id)
                        .delete()
                        .continueWithTask { task ->
                            if (task.isSuccessful)
                                storageRef.child(book.id).delete()
                            else
                                throw Exception(task.exception)
                        }
                        .addOnCompleteListener {
                            value = it.isSuccessful
                        }
            }
        }
    }

    private fun uploadPhoto(book: Book): Task<Uri> {
        compressPhoto(book.coverUrl)
        val storageRef = storageRef.child(book.id)
        return storageRef.putFile(Uri.parse(book.coverUrl))
                .continueWithTask { uploadTask ->
                    uploadTask.result?.storage?.downloadUrl
                }
    }

    private fun compressPhoto(path: String) {
        val imgFile = File(path.substringAfter("file://"))
        val bos = ByteArrayOutputStream()
        val bmp = BitmapFactory.decodeFile(imgFile.absolutePath)
        bmp.compress(Bitmap.CompressFormat.JPEG, 70, bos)
        val fos = FileOutputStream(imgFile)
        fos.write(bos.toByteArray())
        fos.flush()
        fos.close()
    }

    companion object {
        const val BOOKS_KEY = "books"
        const val USER_ID_KEY = "userId"
        const val ID_KEY = "id"
        const val COVER_URL_KEY = "coverUrl"
    }
}