package uz.uzinfocom.myid

import android.app.Activity
import android.content.Context
import android.content.res.Resources.NotFoundException
import android.os.Build
import io.flutter.plugin.common.MethodChannel
import uz.myid.android.sdk.capture.MyIdClient
import uz.myid.android.sdk.capture.MyIdConfig
import uz.myid.android.sdk.capture.model.MyIdBuildMode
import uz.myid.android.sdk.capture.model.MyIdCameraSelector
import uz.myid.android.sdk.capture.model.MyIdCameraShape
import uz.myid.android.sdk.capture.model.MyIdEntryType
import uz.myid.android.sdk.capture.model.MyIdImageFormat
import uz.myid.android.sdk.capture.model.MyIdOrganizationDetails
import uz.myid.android.sdk.capture.model.MyIdResidentType
import uz.myid.android.sdk.capture.model.MyIdResolution
import java.util.Locale

class MyIdSdk(
    private val client: MyIdClient,
    private val activityListener: MyIdSdkActivityListener,
) {

    private var currentFlutterResult: MethodChannel.Result? = null
    private var currentActivity: Activity? = null

    private fun setFlutterResult(result: MethodChannel.Result?) {
        currentFlutterResult = result
        activityListener.setCurrentFlutterResult(result)
    }

    fun setActivity(activity: Activity?) {
        if (activity != null) {
            currentActivity = activity
        }
    }

    fun start(
        config: HashMap<String, Any?>?,
        result: MethodChannel.Result?
    ) {
        setFlutterResult(result)

        try {
            if (config == null) {
                currentFlutterResult?.error(
                    "error",
                    "MyID config is null",
                    null
                )
                setFlutterResult(null)
                return
            }

            val clientId: String
            val clientHash: String
            val clientHashId: String
            val passportData: String
            val dateOfBirth: String
            val minAge: Int
            val sdkHash: String
            val externalId: String
            val threshold: Float
            val buildMode: MyIdBuildMode
            val entryType: MyIdEntryType
            val residency: MyIdResidentType
            val locale: Locale
            val cameraShape: MyIdCameraShape
            val cameraSelector: MyIdCameraSelector
            val resolution: MyIdResolution
            val imageFormat: MyIdImageFormat
            val organizationDetails: MyIdOrganizationDetails
            val distance: Float

            try {
                clientId = config.fetch("clientId")
                clientHash = config.fetch("clientHash")
                clientHashId = config.fetch("clientHashId")
                passportData = config.fetch("passportData")
                dateOfBirth = config.fetch("dateOfBirth")
                minAge = config.fetch("minAge").toIntOrNull() ?: 16
                sdkHash = config.fetch("sdkHash")
                externalId = config.fetch("externalId")
                threshold = config.fetch("threshold").toFloatOrNull() ?: 0.55f
                distance = config.fetch("distance").toFloatOrNull() ?: 0.65f

                buildMode = when (config.fetch("buildMode").uppercase()) {
                    MyIdBuildMode.DEBUG.name -> MyIdBuildMode.DEBUG
                    else -> MyIdBuildMode.PRODUCTION
                }
                entryType = when (config.fetch("entryType").uppercase()) {
                    MyIdEntryType.FACE.name -> MyIdEntryType.FACE
                    else -> MyIdEntryType.AUTH
                }
                residency = when (config.fetch("residency").uppercase()) {
                    MyIdResidentType.USER_DEFINED.name -> MyIdResidentType.USER_DEFINED
                    MyIdResidentType.NON_RESIDENT.name -> MyIdResidentType.NON_RESIDENT
                    else -> MyIdResidentType.RESIDENT
                }
                locale = when (config.fetch("locale").uppercase()) {
                    "ENGLISH" -> Locale("en")
                    "RUSSIAN" -> Locale("ru")
                    else -> Locale("uz")
                }
                cameraShape = when (config.fetch("cameraShape").uppercase()) {
                    MyIdCameraShape.ELLIPSE.name -> MyIdCameraShape.ELLIPSE
                    else -> MyIdCameraShape.CIRCLE
                }
                cameraSelector = when (config.fetch("cameraSelector").uppercase()) {
                    MyIdCameraSelector.BACK.name -> MyIdCameraSelector.BACK
                    else -> MyIdCameraSelector.FRONT
                }
                resolution = when (config.fetch("resolution").uppercase()) {
                    MyIdResolution.RESOLUTION_720.name -> MyIdResolution.RESOLUTION_720
                    else -> MyIdResolution.RESOLUTION_480
                }
                imageFormat = when (config.fetch("imageFormat").uppercase()) {
                    MyIdImageFormat.JPG.name -> MyIdImageFormat.JPG
                    else -> MyIdImageFormat.PNG
                }

                val orgMap = config["organizationDetails"] as? HashMap<String, Any?>

                val drawableName = orgMap?.fetch("logo")
                val drawableId = try {
                    currentActivity?.resIdByName(drawableName, "drawable")
                } catch (e: NotFoundException) {
                    null
                }

                organizationDetails = MyIdOrganizationDetails(
                    phoneNumber = orgMap?.fetch("phone"),
                    logo = drawableId,
                )
            } catch (e: Exception) {
                currentFlutterResult?.error(
                    "error",
                    "MyID config error: ${e.message}",
                    null
                )
                setFlutterResult(null)
                return
            }

            if (currentActivity == null) {
                currentFlutterResult?.error(
                    "error",
                    "Android activity does not exist",
                    null
                )
                setFlutterResult(null)
                return
            }

            try {
                val myIdConfig = MyIdConfig.builder(clientId)
                    .withClientHash(clientHash, clientHashId)
                    .withPassportData(passportData)
                    .withBirthDate(dateOfBirth)
                    .withMinAge(minAge)
                    .withSdkHash(sdkHash)
                    .withExternalId(externalId)
                    .withThreshold(threshold)
                    .withBuildMode(buildMode)
                    .withEntryType(entryType)
                    .withResidency(residency)
                    .withLocale(locale)
                    .withCameraShape(cameraShape)
                    .withCameraSelector(cameraSelector)
                    .withResolution(resolution)
                    .withImageFormat(imageFormat)
                    .withOrganizationDetails(organizationDetails)
                    .withDistance(distance)
                    .build()

                currentActivity?.let {
                    client.startActivityForResult(it, 1, myIdConfig)
                }
            } catch (e: Exception) {
                currentFlutterResult?.error(
                    "error",
                    "Failed to show MyID page: ${e.message}",
                    null
                )
                setFlutterResult(null)
                return
            }
        } catch (e: Exception) {
            currentFlutterResult?.error(
                "error",
                "Unexpected error starting MyID page: ${e.message}",
                null
            )
            setFlutterResult(null)
            return
        }
    }

    private fun <T> HashMap<String, T>.fetch(key: String): String {
        val result = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            getOrDefault(key, "")
        } else {
            if (containsKey(key)) {
                this[key] ?: ""
            } else {
                ""
            }
        }
        return result?.toString().orEmpty()
    }

    private fun Context.resIdByName(resIdName: String?, resType: String): Int {
        resIdName?.let {
            return resources.getIdentifier(it, resType, packageName)
        }
        throw NotFoundException()
    }
}