package com.base.locationsharewhite.ui.locationmap

import android.Manifest
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.app.Dialog
import android.content.Intent
import android.graphics.Color
import android.os.Build
import android.view.LayoutInflater
import android.view.View
import android.view.animation.LinearInterpolator
import androidx.activity.addCallback
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.base.locationsharewhite.BuildConfig
import com.base.locationsharewhite.R
import com.base.locationsharewhite.ads.AdsMgr
import com.base.locationsharewhite.ads.AdsShowCallBack
import com.base.locationsharewhite.bean.ConstObject
import com.base.locationsharewhite.bean.ViewingBean
import com.base.locationsharewhite.databinding.ActivityLocationMapBinding
import com.base.locationsharewhite.fcm.NotificationUiUtil.sendAllAllowedNotification
import com.base.locationsharewhite.helper.BaseActivity
import com.base.locationsharewhite.location.LocationPositionUtils
import com.base.locationsharewhite.location.LocationShareListUtils
import com.base.locationsharewhite.map.MapUtils.addLocationMarker
import com.base.locationsharewhite.map.MapUtils.getLatLngByLocationManager
import com.base.locationsharewhite.service.StayJobService
import com.base.locationsharewhite.service.StayJobService.Companion.requestServiceLocationUpdates
import com.base.locationsharewhite.service.StayNotification.notifyStayNotification
import com.base.locationsharewhite.ui.set.RenameActivity
import com.base.locationsharewhite.ui.set.RenameActivity.Companion.RENAME_VIEWING_NICK_NAME
import com.base.locationsharewhite.ui.views.DialogView.showMapTypeDialog
import com.base.locationsharewhite.ui.views.DialogView.showViewerMoreDialog
import com.base.locationsharewhite.ui.views.LocationPermissionDialog.showLocationAllowAllTimeDialog
import com.base.locationsharewhite.utils.BarUtils
import com.base.locationsharewhite.utils.LogEx
import com.base.locationsharewhite.utils.PermissionUtils.checkAllLocationPermission
import com.base.locationsharewhite.utils.PermissionUtils.checkBackgroundLocationPermission
import com.base.locationsharewhite.utils.PermissionUtils.checkLocationPermission
import com.base.locationsharewhite.utils.PermissionUtils.requestLocationAllowAllTime
import com.base.locationsharewhite.utils.SpStringUtils
import com.base.locationsharewhite.utils.SpStringUtils.VIEWING_NICKNAME_KEY
import com.base.locationsharewhite.utils.SpStringUtils._DEVICE_NICKNAME_
import com.base.locationsharewhite.utils.ToastUtils.toast
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.Marker
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch


class LocationMapActivity : BaseActivity<ActivityLocationMapBinding>(), OnMapReadyCallback {

    private var map: GoogleMap? = null
    private lateinit var locationPresenter: LocationPresenter
    private lateinit var adapter: ViewingAdapter
    private var getLocationJob: Job? = null

    override val binding: ActivityLocationMapBinding by lazy {
        ActivityLocationMapBinding.inflate(layoutInflater)
    }

    private var myMarker: Marker? = null
    private var friendMarker: Marker? = null
    private var currentViewingBean: ViewingBean? = null
    private var allowAllTimeDialog: Dialog? = null


    override fun initView() {
        BarUtils.setStatusBarLightMode(this, true)
        BarUtils.setStatusBarColor(this, Color.TRANSPARENT)
//        binding.root.updatePadding(top = BarUtils.getStatusBarHeight())
        locationPresenter = LocationPresenter(this, lifecycleScope)

        val recreated = changeLanguage(this)
        if (recreated) return

        if (checkAllLocationPermission()) {
            if (AdsMgr.adsConfigBean.functionInShowAd) {
                AdsMgr.showInsert(this, showCallBack = object : AdsShowCallBack() {
                    override fun close(where: Int) {
                        LogEx.logDebug(TAG, "where=$where")
                    }

                    override fun failed(where: Int) {
                        LogEx.logDebug(TAG, "where=$where")
                    }

                    override fun googleFailed(where: Int) {
                        LogEx.logDebug(TAG, "where=$where")
                    }
                })
            }
        }

        val mapFragment =
            supportFragmentManager.findFragmentById(R.id.map) as SupportMapFragment?
        mapFragment?.getMapAsync(this)

        showFriendGuideOrNoFriend()
        initAdapter()
        initViewingData()

        showAllowAllTimeDialog()
    }

    private fun showAllowAllTimeDialog() {
        if (!checkAllLocationPermission()) {
//            toast("显示权限始终允许弹窗")
            if (allowAllTimeDialog == null) {
                allowAllTimeDialog =
                    showLocationAllowAllTimeDialog(
                        setAction = {
                            sendAllAllowedNotification(this)
                            requestLocationAllowAllTime(launcher, jumpOutAction = {
                                LogEx.logDebug(TAG, "jumpOutAction")
                            }, permissionAllowCallBack = {})
                        },
                        dismissAction = {
                            allowAllTimeDialog = null
                        })
            }
        } else {
//            toast("不显示权限始终允许弹窗")
            allowAllTimeDialog?.dismiss()
            allowAllTimeDialog = null

            requestServiceLocationUpdates()
        }
    }

    override fun onResumeOneShoot() {
        super.onResumeOneShoot()
        binding.ivPermission.isVisible = !checkAllLocationPermission()
    }


    private fun initAdapter() {

        adapter = ViewingAdapter(
            itemClick = { viewingBean ->

                if (currentViewingBean?.device != viewingBean.device) {
                    removeOldViewingMarker()
                    currentViewingBean = viewingBean
                    startGetLocationJob()
                }

                changeViewingBeanPosition(true, true, true)
            },
            moreClick = { anchorView, viewingBean: ViewingBean ->
                showViewerMoreDialog(anchorView,
                    renameAction = {
                        startActivity(Intent(this, RenameActivity::class.java).apply {
                            putExtra("doWhat", RENAME_VIEWING_NICK_NAME)
                            putExtra("device", viewingBean.device)
                            putExtra("nickName", viewingBean.localNickName ?: viewingBean.nickname)
                        })
                    },
                    deleteAction = {
                        LocationShareListUtils.deleteShare(viewingBean.device) { result ->
                            runOnUiThread {
                                if (result) {
                                    toast("delete success", true)
                                    binding.ivRefresh.callOnClick()
                                } else {
                                    toast("delete failed", true)
                                }
                            }
                        }
                    }
                )
            }
        )
        binding.rvViewing.adapter = adapter
    }

    private fun cancelGetLocationJob() {
        currentViewingBean = null
        getLocationJob?.cancel()
        getLocationJob = null
        friendMarker?.remove()
    }

    @SuppressLint("NotifyDataSetChanged")
    private fun startGetLocationJob() {
        getLocationJob?.cancel()
        getLocationJob = null
        getLocationJob = lifecycleScope.launch(Dispatchers.IO) {

            while (isActive) {
                currentViewingBean?.let { viewingBean ->
                    LocationPositionUtils.getLocation(viewingBean.device) { locatDate ->
                        currentViewingBean?.locatDate = locatDate
                        lifecycleScope.launch(Dispatchers.Main) {
                            if (BuildConfig.DEBUG) {
//                                toast("getLocation ${locatDate?.latitude} ${locatDate?.longitude}")
                            }
                            val viewing = adapter.items.findLast { it.device == viewingBean.device }
                            viewing?.locatDate = locatDate
                            adapter.notifyDataSetChanged()

                            changeViewingBeanPosition(false, false, false)
                        }
                    }
                }
                if (currentViewingBean == null) {
                    friendMarker?.remove()
                    friendMarker = null
                }
                delay(10 * 1000L)
            }
        }
    }

    private fun showFriendGuideOrNoFriend() {
        if (ConstObject.noShowFriendsShareGuide) {
            binding.llFriendsGuide.visibility = View.GONE
            binding.llNoFriend.visibility = View.VISIBLE
        } else {
            binding.llFriendsGuide.visibility = View.VISIBLE
            binding.llNoFriend.visibility = View.GONE
        }
    }

    private fun initViewingData() {
        LocationShareListUtils.getShareList(viewerListCallBack = { viewerList ->
            val size = viewerList.size
            val desc = if (size == 0) {
                "Location sharing not enable yet"
            } else {
                "Sharing location with $size people"
            }
            notifyStayNotification(this.applicationContext, desc)
        },
            viewingListCallBack = { viewing ->
                val nickList = SpStringUtils.getSpStringList(VIEWING_NICKNAME_KEY)
                viewing.map { changeLocalNickName(it, nickList) }
                runOnUiThread {
                    if (viewing.isEmpty()) {
                        showFriendGuideOrNoFriend()
                        adapter.submitList(listOf())
                        cancelGetLocationJob()
                    } else {
                        binding.llFriendsGuide.visibility = View.GONE
                        binding.llNoFriend.visibility = View.GONE
                        binding.rvViewing.visibility = View.VISIBLE
                        adapter.submitList(viewing)
                    }
                }
            }

        )
    }

    override fun initListener() {
        super.initListener()

        onBackPressedDispatcher.addCallback {
            if (AdsMgr.adsConfigBean.functionBackShowAd) {
                AdsMgr.showInsert(this@LocationMapActivity, false, object : AdsShowCallBack() {
                    override fun close(where: Int) {
                        finishToMain()
                    }

                    override fun failed(where: Int) {
                        finishToMain()
                    }

                    override fun googleFailed(where: Int) {
                        finishToMain()
                    }
                })
            } else {
                finishToMain()
            }
        }
        binding.ivFanhui.setOnClickListener {
            onBackPressedDispatcher.onBackPressed()
        }

        binding.ivChangeMapType.setOnClickListener {
            map?.let { showMapTypeDialog(it) }
        }

        binding.tvGotIt.setOnClickListener {
            binding.llFriendsGuide.visibility = View.GONE
            if (adapter.items.isEmpty()) {
                binding.llNoFriend.visibility = View.VISIBLE
            }
        }
        binding.tvNoShowAgain.setOnClickListener {
            ConstObject.noShowFriendsShareGuide = true
            binding.llFriendsGuide.visibility = View.GONE
            if (adapter.items.isEmpty()) {
                binding.llNoFriend.visibility = View.VISIBLE
            }
        }
        binding.ivLocation.setOnClickListener {
            changeMyLocation(locationPresenter.getMyLocation(), true, true, true)
        }
        binding.ivRefresh.setOnClickListener {
            AdsMgr.showInsert(this, false, object : AdsShowCallBack() {
                override fun close(where: Int) {
                    startRefresh()
                }

                override fun failed(where: Int) {
                    startRefresh()
                }

                override fun googleFailed(where: Int) {
                    startRefresh()
                }
            })

        }
        binding.bottomSheet.setOnClickListener { }
        binding.ivPermission.setOnClickListener {
            showAllowAllTimeDialog()
        }
    }

    fun startRefresh() {
        startRefreshAnimation()
        lifecycleScope.launch(Dispatchers.Main) {
            delay(2000)
            stopRefreshAnimation()
        }
        initViewingData()
    }

    private var valueAnimator: ValueAnimator? = null
    private fun startRefreshAnimation() {
        if (valueAnimator == null) {
            valueAnimator = ValueAnimator.ofFloat(0f, 360f)
            valueAnimator?.run {
                duration = 1000
                repeatMode = ValueAnimator.RESTART
                repeatCount = ValueAnimator.INFINITE
                interpolator = LinearInterpolator()
                addUpdateListener {
                    binding.ivRefresh.rotation = it.animatedValue as Float
                }
                start()
            }
        }
    }

    private fun stopRefreshAnimation() {
        valueAnimator?.cancel()
        valueAnimator = null
        binding.ivRefresh.rotation = 0f
    }

    override fun onMapReady(googleMap: GoogleMap) {
        LogEx.logDebug(TAG, "onMapReady")
        map = googleMap

        LogEx.logDebug(TAG, "onMapReady")
        val flag = changeMyLocation(locationPresenter.getMyLocation(), true, true, true)

        if (!flag) {
            StayJobService.oneShotLocationCallBack = {
                changeMyLocation(locationPresenter.getMyLocation(), true, true, true)
            }
        }
        locationPresenter.refreshLocationCallBack = {
            LogEx.logDebug(TAG, "myLocation ${it}")
            changeMyLocation(it, false, false, false)
        }
    }

    /**
     * 设置自己位置
     */
    private fun changeMyLocation(
        latLng: LatLng?,
        followCamera: Boolean,
        resetZoom: Boolean,
        changeZIndex: Boolean
    ): Boolean {
        initMyLocationMarker()

        if (changeZIndex) {
            changeMarkerZIndex(true)
        }

        latLng?.let {
            myMarker?.position = it

            if (followCamera) {
                if (resetZoom) {
                    map?.moveCamera(CameraUpdateFactory.newLatLngZoom(it, 15f))
                    myMarker?.showInfoWindow()
                } else {
                    map?.moveCamera(CameraUpdateFactory.newLatLng(it))
                }
            }
            return true
        }
        return false
    }

    /**
     * 初始化自己Marker
     */
    private fun initMyLocationMarker() {
        if (myMarker == null) {
            var myLatLng: LatLng? = getLatLngByLocationManager()
            if (myLatLng == null) {
                myLatLng = StayJobService.googleLocation
            }
            myLatLng?.let {
                LogEx.logDebug(TAG, "getLastKnowLocation ${myLatLng.latitude} ${myLatLng.longitude}")
                val myAvatar = LayoutInflater.from(this).inflate(R.layout.avatar_me, null)
                myMarker = map?.addLocationMarker(myAvatar, myLatLng, getString(R.string.me))
            }
        }
    }

    /**
     * 改变他人位置
     */
    private fun changeViewingBeanPosition(changeCamera: Boolean, resetZoom: Boolean, changeZIndex: Boolean) {
        currentViewingBean?.let { viewingBean ->
            viewingBean.locatDate?.let { locatDate ->

                val latLng = LatLng(locatDate.latitude, locatDate.longitude)
                initViewingMarker(latLng, viewingBean.nickname)

                setViewingBeanMarker(latLng, changeCamera, resetZoom, changeZIndex)

            }
        }
    }

    /**
     * 初始化他人Marker
     */
    private fun initViewingMarker(latLng: LatLng, nickname: String) {
        if (friendMarker == null) {
            val friendAvatar = LayoutInflater.from(this).inflate(R.layout.avatar_friend, null)
            friendMarker = map?.addLocationMarker(friendAvatar, latLng, nickname)
        }

    }

    /**
     * 移除旧的他人Marker
     */
    private fun removeOldViewingMarker() {
        friendMarker?.remove()
        friendMarker = null
    }

    /**
     * 移动他人Marker
     */
    private fun setViewingBeanMarker(
        latLng: LatLng,
        changeCamera: Boolean,
        resetZoom: Boolean,
        changeZIndex: Boolean
    ) {
        if (changeCamera) {
            if (resetZoom) {
                map?.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15f))
                friendMarker?.showInfoWindow()
            } else {
                map?.moveCamera(CameraUpdateFactory.newLatLng(latLng))
            }
        }
        friendMarker?.position = latLng
        LogEx.logDebug(TAG, "Viewing ${latLng}")
        if (changeZIndex) {
            changeMarkerZIndex(false)
        }
    }

    private fun changeMarkerZIndex(isShowMe: Boolean) {
        if (isShowMe) {
            myMarker?.zIndex = 2f
            friendMarker?.zIndex = 1f
        } else {
            myMarker?.zIndex = 1f
            friendMarker?.zIndex = 2f
        }
    }

    override fun onStop() {
        super.onStop()
        locationPresenter.cancelUploadJob()
    }

    override fun onPause() {
        super.onPause()
        StayJobService.getGoogleServiceLocationDelay = 60
    }

    override fun onResume() {
        super.onResume()

//        val isRecreate = updateAppLanguage(MyApplication.locationMapLanguage) {
//            MyApplication.locationMapLanguage = it
//        }
//        if (isRecreate) {
//            return
//        }
        StayJobService.getGoogleServiceLocationDelay = 30

        if (!checkLocationPermission() || !checkBackgroundLocationPermission()) {
            binding.ivPermission.visibility = View.VISIBLE
        } else {
            binding.ivPermission.visibility = View.GONE
            locationPresenter.startUploadMyLocation()
            requestServiceLocationUpdates()
        }
        refreshNickName()
    }

    @SuppressLint("NotifyDataSetChanged")
    private fun refreshNickName() = lifecycleScope.launch(Dispatchers.IO) {
        val nickList = SpStringUtils.getSpStringList(VIEWING_NICKNAME_KEY)

        adapter.items.map { viewing ->
            changeLocalNickName(viewing, nickList)
        }
        launch(Dispatchers.Main) {
            adapter.notifyDataSetChanged()
        }
    }

    private fun changeLocalNickName(viewingBean: ViewingBean, nickList: List<String>) {
        val deviceNicknameSp = nickList.find { it.contains(viewingBean.device) }
        deviceNicknameSp?.let { sp ->
            runCatching {
                val localNickName = sp.split(_DEVICE_NICKNAME_)[1]
                viewingBean.localNickName = localNickName
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        notifyStayNotification(this.applicationContext, "Location sharing not enable yet")
    }

}