package it.danieleverducci.openweddingapp

import android.Manifest
import android.app.Application
import android.content.ActivityNotFoundException
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.provider.MediaStore
import android.util.Log
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.animation.Animation
import android.view.animation.AnimationUtils
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import androidx.drawerlayout.widget.DrawerLayout
import androidx.navigation.findNavController
import androidx.navigation.ui.*
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import com.android.volley.VolleyError
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.navigation.NavigationView
import com.squareup.picasso.Picasso
import it.danieleverducci.openweddingapp.entities.GalleryItem
import it.danieleverducci.openweddingapp.entities.RemoteSettings
import it.danieleverducci.openweddingapp.networking.RemoteSettingsNet
import it.danieleverducci.openweddingapp.networking.StaticItemNet
import it.danieleverducci.openweddingapp.ui.LoginActivity
import it.danieleverducci.openweddingapp.ui.gallery.GalleryFragment
import it.danieleverducci.openweddingapp.utils.*
import java.io.File
import java.io.IOException
import java.util.concurrent.TimeUnit


class MainActivity : AppCompatActivity() {
    companion object {
        const val MY_PERMISSIONS_REQUEST = 5862
        val REQUEST_IMAGE_CAPTURE = 19437
        val REQUEST_IMAGE_SELECT_FROM_GALLERY = 53213
        val TAG = "MainActivity"
    }
    var capturedImageFile: File? = null
    lateinit var drawerToggle: ActionBarDrawerToggle

    private lateinit var appBarConfiguration: AppBarConfiguration
    private lateinit var drawer: DrawerLayout

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val toolbar: Toolbar = findViewById(R.id.toolbar)
        setSupportActionBar(toolbar)

        initNotificationsWorker()
        initUi()
    }

    override fun onPostCreate(savedInstanceState: Bundle?) {
        super.onPostCreate(savedInstanceState)
        drawerToggle.syncState()
    }

    override fun onStart() {
        super.onStart()
        checkStagingInstance()
        updateRemoteSettings()

        // If first run
        if (SharedPreferencesManager.isFirstAppRun(this)) {
            // go to Info fragment
            val navController = findNavController(R.id.nav_host_fragment)
            navController.navigate(R.id.nav_info)
            // show menu after 1 sec
            Handler(Looper.getMainLooper()).postDelayed({
                drawer.openDrawer(Gravity.LEFT, true)
            }, 1000)
        }
    }

    override fun onBackPressed() {
        val navController = findNavController(R.id.nav_host_fragment)
        // If already on first screen, show menu instead of closing app right away
        if (navController.currentDestination?.id == R.id.nav_gallery && !drawer.isDrawerOpen(Gravity.LEFT)) {
            drawer.openDrawer(Gravity.LEFT, true)
            return
        }
        super.onBackPressed()
    }

    private fun initNotificationsWorker() {
        val wReq = PeriodicWorkRequestBuilder<NotificationWorker>(30, TimeUnit.MINUTES)
            .build()
        WorkManager.getInstance(this).enqueueUniquePeriodicWork("dernotif",
            ExistingPeriodicWorkPolicy.REPLACE, wReq)
    }

    private fun initUi() {
        val navView: NavigationView = findViewById(R.id.nav_view)
        drawer = findViewById(R.id.drawer_layout)
        val navController = findNavController(R.id.nav_host_fragment)

        // Set drawer toggle button
        supportActionBar!!.setDisplayHomeAsUpEnabled(true)
        drawerToggle = ActionBarDrawerToggle(this,  drawer, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
        drawer.addDrawerListener(drawerToggle)
        drawerToggle.syncState()

        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        appBarConfiguration = AppBarConfiguration(
            setOf(
                R.id.nav_gallery, R.id.nav_presence, R.id.nav_location, R.id.nav_food_menu,
                R.id.nav_wedding_gift, R.id.nav_info, R.id.nav_attendee_gift,
                R.id.nav_privacy, R.id.nav_table, R.id.nav_places
            ), drawer
        )
        setupActionBarWithNavController(navController, appBarConfiguration)
        navView.setupWithNavController(navController)
        navView.setNavigationItemSelectedListener {
            drawer.closeDrawer(Gravity.LEFT, true)

            // If navigating to the same fragment, do nothing
            if(it.itemId == navController.currentDestination?.id)
                return@setNavigationItemSelectedListener true

            // Otherwise, navigate to fragment and close drawer
            return@setNavigationItemSelectedListener NavigationUI.onNavDestinationSelected(it, navController)
        }

        // Set user name and picture
        val headerView = navView.getHeaderView(0)
        val user = (application as DeRApplication).token?.user
        if (user == null) {
            startActivity(Intent(this, LoginActivity::class.java))
            finish()
            return
        }
        headerView.findViewById<TextView>(R.id.nav_header_user_name).text = "${user.name} ${user.surname}"

        if (user.picture != null && user.picture.isNotEmpty()) {
            val userBadge = headerView.findViewById<ImageView>(R.id.nav_header_user_badge)
            userBadge.visibility = View.VISIBLE
            Picasso.get()
                .load(user.pictureUrl)
                .placeholder(R.drawable.placeholder)
                .error(R.drawable.placeholder)
                .into(userBadge)
        } else {
            val userBadge = headerView.findViewById<TextView>(R.id.nav_header_user_text_badge)
            userBadge.visibility = View.VISIBLE
            userBadge.text = user.name.substring(0,1)
            ViewUtils.colorizeUserBadge(userBadge, user)
        }

        // Take Photo Fab onClick
        val fabTakePhoto: FloatingActionButton = findViewById(R.id.fab_take_photo)
        fabTakePhoto.setOnClickListener { _ ->
            // Check if the photo sharing is enabled
            if (
                !(application as DeRApplication).remoteSettings.photoSharingEnabled &&
                !(application as DeRApplication).token!!.user.admin
            ) {
                // Display "photo sharing will be enabled on wedding day"
                showPhotoSharindDisabledDialog()
                return@setOnClickListener
            }
            // Request camera permission
            if (ContextCompat.checkSelfPermission(this,
                    Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED) {
                // Request permission
                ActivityCompat.requestPermissions(this,
                    arrayOf(Manifest.permission.CAMERA),
                    MY_PERMISSIONS_REQUEST)
            } else {
                // Permission has already been granted: acquire photo
                acquirePhoto();
            }
        }

        // Select Photo Fab onClick
        val fabSelectPhoto: FloatingActionButton = findViewById(R.id.fab_select_photo)
        fabSelectPhoto.setOnClickListener { _ ->
            // Check if the photo sharing is enabled
            if (
                !(application as DeRApplication).remoteSettings.photoSharingEnabled &&
                !(application as DeRApplication).token!!.user.admin
            ) {
                // Display "photo sharing will be enabled on wedding day"
                showPhotoSharindDisabledDialog()
                return@setOnClickListener
            }
            val intent = Intent()
            intent.type = "image/*"
            intent.action = Intent.ACTION_GET_CONTENT
            intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
            startActivityForResult(Intent.createChooser(intent, getString(R.string.photouploading_fab_intent)), REQUEST_IMAGE_SELECT_FROM_GALLERY)
        }
    }

    private fun acquirePhoto() {
        // Switch fragment to social
        val navController = findNavController(R.id.nav_host_fragment)
        navController.navigate(R.id.nav_gallery)

        // Start capture activity
        Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
            takePictureIntent.resolveActivity(packageManager)?.also {
                val photoFile: File? = try {
                    capturedImageFile = FileUtils.createImageFile(this)
                    capturedImageFile
                } catch (ex: IOException) {
                    Log.e(TAG, "Unable to create temp camera file: ${ex}")
                    null
                }
                // Continue only if the File was successfully created
                photoFile?.also {
                    val photoURI: Uri = FileProvider.getUriForFile(
                        this,
                        "it.danieleverducci.openweddingapp.fileprovider",
                        it
                    )
                    takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
                    startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
                }
            }
        }
    }

    override fun onSupportNavigateUp(): Boolean {
        val navController = findNavController(R.id.nav_host_fragment)
        return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        // User took photo from app
        if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK && capturedImageFile != null) {
            // Some camera apps (like OpenCamera) returns the image in the standard sensor orientation and save the rotation in the exif data.
            // In this case, we must rotate the image on our own.
            if ((application as DeRApplication).remoteSettings.rotateToExifData)
                ImageUtils.rotateImageIfRequired(capturedImageFile!!)

            val gi = GalleryItem(capturedImageFile!!.path, capturedImageFile!!.path, (application as DeRApplication).token!!.user)

            // Add photo to list
            val navHost = supportFragmentManager.findFragmentById(R.id.nav_host_fragment)
            navHost?.let { navFragment ->
                navFragment.childFragmentManager.primaryNavigationFragment?.let {currentFragment->
                    if (currentFragment is GalleryFragment) {
                        currentFragment.onPhotoTaken(gi)
                    }
                }
            }
            capturedImageFile = null
        }

        // User selected photo from gallery (initiated from app)
        if (requestCode == REQUEST_IMAGE_SELECT_FROM_GALLERY && resultCode == RESULT_OK && data != null) {
            val shareIntent = Intent(this, ShareActivity::class.java)
            shareIntent.type = "image/*"
            if (data.data != null) {
                // Single image
                shareIntent.action = Intent.ACTION_SEND
                shareIntent.putExtra(Intent.EXTRA_STREAM, data.data)
            } else if (data.clipData != null) {
                // Multiple images
                shareIntent.action = Intent.ACTION_SEND_MULTIPLE
                val uris = ArrayList<Uri>()
                for (i in 0..data.clipData!!.itemCount - 1)
                    uris.add(data.clipData!!.getItemAt(i).uri)
                shareIntent.putExtra(Intent.EXTRA_STREAM, uris)
            } else {
                // Invalid intent
                Toast.makeText(this, R.string.photouploading_unsupported, Toast.LENGTH_SHORT).show()
                return
            }
            startActivity(shareIntent)
        }
    }

    public fun onLogoutButtonClicked(v: View) {
        logout()
    }

    public fun logout() {
        // Remove token
        (application as DeRApplication).token = null
        // Remove data
        (application as DeRApplication).clearData()
        // Go to login
        val i = Intent(this, LoginActivity::class.java)
        startActivity(i)
        finish()
    }

    public fun showFab(show: Boolean) {
        animateFab(findViewById<View>(R.id.fab_take_photo), show)
        animateFab(findViewById<View>(R.id.fab_select_photo), show)
    }

    private fun animateFab(view: View, show: Boolean) {
        val animation = AnimationUtils.loadAnimation(this,
            if (show) R.anim.slide_in_right else R.anim.slide_out_right
        )
        animation.setAnimationListener(object : Animation.AnimationListener {
            override fun onAnimationStart(p0: Animation?) {}

            override fun onAnimationEnd(p0: Animation?) {
                view.visibility = if (show) View.VISIBLE else View.GONE
            }

            override fun onAnimationRepeat(p0: Animation?) {}

        })
        view.startAnimation(animation)
    }

    private fun showPhotoSharindDisabledDialog() {
        val builder: AlertDialog.Builder = AlertDialog.Builder(this@MainActivity)
        val dialogView: View =
            LayoutInflater.from(this@MainActivity).inflate(R.layout.dialog_photosharingdisabled, null, false)
        builder.setView(dialogView)
        val alertDialog: AlertDialog = builder.create()
        alertDialog.show()
    }

    private fun updateRemoteSettings() {
        RemoteSettingsNet(this@MainActivity).getItem(object: StaticItemNet.OnItemObtainedListener<RemoteSettings> {
            override fun OnItemObtained(item: RemoteSettings) {
                val rsLocalVersion = (application as DeRApplication).remoteSettings.version
                if(item.version > rsLocalVersion) {
                    SharedPreferencesManager.saveRemoteSettings(this@MainActivity, item)
                    Log.d(TAG, "Updated remoteSettings: local ${rsLocalVersion}, remote ${item.version}")
                    checkAppIsUpToDate()
                } else {
                    Log.d(TAG, "RemoteSettings up to date: local ${rsLocalVersion}, remote ${item.version}")
                    checkAppIsUpToDate()
                }
            }

            override fun OnError(error: VolleyError) {
                if (error is com.android.volley.NoConnectionError) {
                    val app = (application as DeRApplication)
                    if (!app.askedConnectingToWeddingWifi) {
                        WifiUtils.askToAddWeddingNetworks(this@MainActivity, app.remoteSettings.wifiNetworks)
                        app.askedConnectingToWeddingWifi = true
                    }
                } else {
                    Log.d(TAG, "Unable to update remote settings: ${error}")
                }
            }

        })
    }

    private fun checkAppIsUpToDate() {
        if (BuildConfig.VERSION_CODE < (application as DeRApplication).remoteSettings.appVersion) {
            // Notify user about the update
            this.let {
                val builder = AlertDialog.Builder(it, R.style.AlertDialogCustom)
                builder.apply {
                    setPositiveButton(android.R.string.ok) { _, _ ->
                        // User clicked OK button
                        try {
                            startActivity(
                                Intent(
                                    Intent.ACTION_VIEW,
                                    Uri.parse("market://details?id=$packageName")
                                )
                            )
                        } catch (e: ActivityNotFoundException) {
                            startActivity(
                                Intent(
                                    Intent.ACTION_VIEW,
                                    Uri.parse("https://play.google.com/store/apps/details?id=$packageName")
                                )
                            )
                        }
                    }
                    setNegativeButton(android.R.string.cancel) { dialog, _ ->
                        dialog.dismiss()
                    }
                }
                builder.setMessage(R.string.update_dialog_message)
                    .setTitle(R.string.update_dialog_title).create()
                builder.show()
            }
        }
    }

    private fun checkStagingInstance() {
        if (Config.BASE_URL.contains("staging"))
            Toast.makeText(this, "!!! STAGING INSTANCE !!!", Toast.LENGTH_LONG).show()
    }
}
