package ae.sdg.uaepasssample

import ae.sdg.libraryuaepass.*
import ae.sdg.libraryuaepass.UAEPassController.downloadDocument
import ae.sdg.libraryuaepass.UAEPassController.getAccessCode
import ae.sdg.libraryuaepass.UAEPassController.getAccessToken
import ae.sdg.libraryuaepass.UAEPassController.getUserProfile
import ae.sdg.libraryuaepass.UAEPassController.resume
import ae.sdg.libraryuaepass.UAEPassController.signDocument
import ae.sdg.libraryuaepass.business.Environment
import ae.sdg.libraryuaepass.business.documentsigning.model.DocumentSigningRequestParams
import ae.sdg.libraryuaepass.business.profile.model.ProfileModel
import ae.sdg.libraryuaepass.utils.FileUtils.saveToExternalStorage
import ae.sdg.uaepasssample.databinding.ActivityMainBinding
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.View
import android.webkit.CookieManager
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.google.gson.Gson
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.nio.charset.Charset

class MainActivity : AppCompatActivity(), View.OnClickListener {

    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)


        binding.loginCodeButton.setOnClickListener(this)
        binding.loginButton.setOnClickListener(this)
        binding.documentButton.setOnClickListener(this)
        binding.profileButton.setOnClickListener(this)
        binding.reset.setOnClickListener(this)
        setEnvironment()
    }

    private fun setEnvironment() {
        val env = when (UAEPassRequestModels.UAE_PASS_ENVIRONMENT) {
            Environment.QA -> {
                "QA"
            }
            Environment.STAGING -> {
                "STAGING"
            }
            Environment.PRODUCTION -> {
                "PRODUCTION"
            }
            else -> {
                "PRODUCTION"
            }
        }
        binding.environmentTextView.text = "Environment: $env"
    }

    override fun onClick(v: View) {
        when (v.id) {
            R.id.login_code_button -> code
            R.id.login_button -> login()
            R.id.document_button -> writePermission
            R.id.profile_button -> profile
            R.id.reset -> clearData()
        }
    }

    /**
     * Ask user for WRITE_EXTERNAL_STORAGE permission to save downloaded document.
     */
    private val writePermission: Unit
        private get() {
            if (ContextCompat.checkSelfPermission(
                    this@MainActivity,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE
                )
                != PackageManager.PERMISSION_GRANTED
            ) {
                if (ActivityCompat.shouldShowRequestPermissionRationale(
                        this@MainActivity,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE
                    )
                ) {
                    Toast.makeText(
                        this@MainActivity,
                        "WRITE_EXTERNAL_STORAGE Permission is required to save the document",
                        Toast.LENGTH_LONG
                    ).show()
                } else {
                    ActivityCompat.requestPermissions(
                        this@MainActivity, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
                        PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE
                    )
                }
            } else {
                signDocument()
            }
        }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<String>, grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE) { // If request is cancelled, the result arrays are empty.
            if (grantResults.size > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED
            ) {
                signDocument()
            } else {
                Toast.makeText(
                    this@MainActivity,
                    "WRITE_EXTERNAL_STORAGE Permission is required to save the document",
                    Toast.LENGTH_LONG
                ).show()
            }
        }
    }

    /**
     * Login with UAE Pass and get the access Code.
     */
    private val code: Unit
        private get() {
            val requestModel = UAEPassRequestModels.getAuthenticationRequestModel(this@MainActivity)
            getAccessCode(this@MainActivity, requestModel, object : UAEPassAccessCodeCallback {
                override fun getAccessCode(code: String?, error: String?) {
                    if (error != null) {
                        Toast.makeText(
                            this@MainActivity,
                            "Error while getting access token",
                            Toast.LENGTH_SHORT
                        ).show()
                    } else {
                        Toast.makeText(
                            this@MainActivity,
                            "Access Code Received",
                            Toast.LENGTH_SHORT
                        ).show()
                    }
                }
            })
        }

    /**
     * Login with UAE Pass and get the access token.
     */
    private fun login() {
        val requestModel = UAEPassRequestModels.getAuthenticationRequestModel(this@MainActivity)
        getAccessToken(this@MainActivity, requestModel, object : UAEPassAccessTokenCallback {
            override fun getToken(accessToken: String?, state: String, error: String?) {
                if (error != null) {
                    Toast.makeText(
                        this@MainActivity,
                        "Error while getting access token",
                        Toast.LENGTH_SHORT
                    ).show()
                } else {
                    Toast.makeText(this@MainActivity, "Access Token Received", Toast.LENGTH_SHORT)
                        .show()
                }
            }
        })
    }

    /**
     * Get User Profile from UAE Pass.
     */
    private val profile: Unit
        private get() {
            val requestModel = UAEPassRequestModels.getProfileRequestModel(this@MainActivity)
            getUserProfile(this@MainActivity, requestModel, object : UAEPassProfileCallback {
                override fun getProfile(
                    profileModel: ProfileModel?,
                    state: String,
                    error: String?
                ) {
                    if (error != null) {
                        Toast.makeText(
                            this@MainActivity,
                            "Error while getting access token",
                            Toast.LENGTH_SHORT
                        ).show()
                    } else {
                        val name = profileModel!!.firstnameEN + " " + profileModel.lastnameEN
                        Toast.makeText(this@MainActivity, "Welcome $name", Toast.LENGTH_SHORT)
                            .show()
                    }
                }
            })
        }

    /**
     * Sign Document Using UAE Pass.
     */
    private fun signDocument() {
        val file = loadDocumentFromAssets()
        val documentSigningParams = loadDocumentSigningJson()
        documentSigningParams?.let {
            val requestModel = UAEPassRequestModels.getDocumentRequestModel(file, it)
            signDocument(this@MainActivity, requestModel, object : UAEPassDocumentSigningCallback {
                override fun getDocumentUrl(spId: String?, documentURL: String?, error: String?) {
                    if (error != null) {
                        Toast.makeText(
                            this@MainActivity,
                            "Error while getting access token",
                            Toast.LENGTH_SHORT
                        ).show()
                    } else {
                        Toast.makeText(
                            this@MainActivity,
                            "Document Signed Successfully",
                            Toast.LENGTH_SHORT
                        ).show()
                        downloadDocument(file.name, documentURL)
                    }
                }
            })
        }
    }

    /**
     * Load Document Signing Json from assets.
     *
     * @return DocumentSigningRequestParams Mandatory Parameters
     */
    private fun loadDocumentSigningJson(): DocumentSigningRequestParams? {
        var json: String? = null
        json = try {
            val `is` = assets.open("testSignData.json")
            val size = `is`.available()
            val buffer = ByteArray(size)
            `is`.read(buffer)
            `is`.close()
            String(buffer, Charset.forName("UTF-8"))
        } catch (ex: IOException) {
            ex.printStackTrace()
            return null
        }
        return Gson().fromJson(json, DocumentSigningRequestParams::class.java)
    }

    /**
     * Load PDF File from assets for signing.
     *
     * @return File PDF file.
     */
    private fun loadDocumentFromAssets(): File {
        val f = File("$filesDir/dummy.pdf")
        try {
            val `is` = assets.open("dummy.pdf")
            val size = `is`.available()
            val buffer = ByteArray(size)
            `is`.read(buffer)
            `is`.close()
            val fos = FileOutputStream(f)
            fos.write(buffer)
            fos.close()
        } catch (e: Exception) {
            throw RuntimeException(e)
        }
        return f
    }

    /**
     * Download the signed document from UAE Pass.
     *
     * @param documentName Document Name with which the document will be saved after downloading.
     * @param documentURL  Document URL received after signing the document.
     */
    private fun downloadDocument(documentName: String, documentURL: String?) {
        val requestModel =
            UAEPassRequestModels.getDocumentDownloadRequestModel(documentName, documentURL)
        downloadDocument(this@MainActivity, requestModel, object : UAEPassDocumentDownloadCallback {
            override fun getDocument(documentBytes: ByteArray?, error: String?) {
                val result = saveToExternalStorage(documentName, documentBytes!!)
                if (result) {
                    Toast.makeText(
                        this@MainActivity,
                        "File Successfully downloaded in Downloads folder.",
                        Toast.LENGTH_LONG
                    ).show()
                } else {
                    Toast.makeText(this@MainActivity, "File Download Failed.", Toast.LENGTH_LONG)
                        .show()
                }
            }
        })
    }

    /**
     * Clear Webview data to open UAE Pass app again.
     */
    private fun clearData() {
        CookieManager.getInstance().removeAllCookies { }
        CookieManager.getInstance().flush()
    }

    //UAE PASS START -- Callback to handle UAE Pass callback
    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        handleIntent(intent)
    }

    private fun handleIntent(intent: Intent?) {
        if (intent != null && intent.data != null) {
            if (BuildConfig.URI_SCHEME == intent.data!!.scheme) {
                resume(intent.dataString)
            }
        }
    } //UAE PASS END -- Callback to handle UAE Pass callback

    companion object {
        private const val PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 12
    }
}