package com.aaron.kakao.hospitalmapfortube.ui.main

import android.databinding.ObservableBoolean
import com.aaron.kakao.hospitalmapfortube.core.BaseViewModel
import com.aaron.kakao.hospitalmapfortube.data.remote.api.MapAPI
import com.aaron.kakao.hospitalmapfortube.data.remote.model.*
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import net.daum.mf.map.api.MapPoint

/**
 * Created by aaron on 2020-03-26
 */

class MainViewModel(private val api: MapAPI) : BaseViewModel() {
    // 콜백 프로퍼티
    lateinit var getCategories: (MutableList<Document>, Boolean) -> Unit
    lateinit var categoryClickEvent: () -> Unit
    lateinit var refreshClickEvent: () -> Unit

    // 카테고리 리스트 노출 여부
    val isShowLocationList = ObservableBoolean(false)
    // 더보기 버튼 노출 여부
    val isShowMore = ObservableBoolean(false)
    // 병원 버튼 활성화 여부
    val isHospitalEnabled = ObservableBoolean(false)
    // 약국 버튼 활성화 여부
    val isPharmacyEnabled = ObservableBoolean(false)
    // 주유 버튼 활성화 여부
    val isOilEnabled = ObservableBoolean(false)
    // 새로고침 버튼 활성화 여부
    val isRefreshEnabled = ObservableBoolean(false)
    // 로딩바 노출 여부
    val isLoading = ObservableBoolean(false)
    private val locationList = mutableListOf<Document>()

    var currentHospitalPage = 1
    var currentPharmacyPage = 1
    var currentOilPage = 1
    var isHospitalPageEnd = false
    var isPharmacyPageEnd = false
    var isOilPageEnd = false
    var isMore = false
    val isAllCategoryDisabled
        get() = !isHospitalEnabled.get() && !isPharmacyEnabled.get() && !isOilEnabled.get()

    /**
     * 카테고리 정보 API 호출
     */
    fun getCategories(mapPoint: MapPoint) {
        locationList.clear()
        val requests = getMergeRequest(mapPoint)
        if (requests.isNotEmpty()) {
            addToDisposable(
                Observable.mergeDelayError(getMergeRequest(mapPoint))
                    .doOnSubscribe { isLoading.set(true) }
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe({
                        if (it.documents.isNotEmpty()) {
                            locationList.addAll(it.documents)
                            checkEnd(it)
                        }
                    }, {
                        isLoading.set(false)
                        it.printStackTrace()
                    }, {
                        isLoading.set(false)
                        if (locationList.isNotEmpty()) {
                            getCategories(locationList, isMore)
                        }
                    })
            )
        } else {
            isMore = false
            getCategories(locationList, isMore)
        }
    }

    /**
     * 카테고리 API 마지막 페이지 체크
     */
    private fun checkEnd(category: Category?) {
        if (category?.meta?.is_end!!) {
            when (category.documents[0].category_group_code) {
                "HP8" -> isHospitalPageEnd = true
                "PM9" -> isPharmacyPageEnd = true
                "OL7" -> isOilPageEnd = true
            }
        }
    }

    /**
     * 활성화되어 있는 카테고리 API 요청 가져오기
     */
    private fun getMergeRequest(mapPoint: MapPoint): List<Observable<Category>> {
        val apiList = mutableListOf<Observable<Category>>()
        if (isHospitalEnabled.get() && !isHospitalPageEnd) {
            apiList.add(
                api.getCategory(mutableMapOf(
                    "x" to "${mapPoint.mapPointGeoCoord.longitude}",
                    "y" to "${mapPoint.mapPointGeoCoord.latitude}",
                    "sort" to "distance",
                    "category_group_code" to CATEGORY_HOSPITAL,
                    "page" to currentHospitalPage.toString()
                ))
                    .subscribeOn(Schedulers.io()).toObservable()
            )
        }
        if (isPharmacyEnabled.get() && !isPharmacyPageEnd) {
            apiList.add(
                api.getCategory(mutableMapOf(
                    "x" to "${mapPoint.mapPointGeoCoord.longitude}",
                    "y" to "${mapPoint.mapPointGeoCoord.latitude}",
                    "sort" to "distance",
                    "category_group_code" to CATEGORY_PHARMACY,
                    "page" to currentPharmacyPage.toString()
                ))
                    .subscribeOn(Schedulers.io()).toObservable()
            )
        }
        if (isOilEnabled.get() && !isOilPageEnd) {
            apiList.add(
                api.getCategory(mutableMapOf(
                    "x" to "${mapPoint.mapPointGeoCoord.longitude}",
                    "y" to "${mapPoint.mapPointGeoCoord.latitude}",
                    "sort" to "distance",
                    "category_group_code" to CATEGORY_OIL,
                    "page" to currentOilPage.toString()
                ))
                    .subscribeOn(Schedulers.io()).toObservable()
            )
        }

        return apiList
    }

    /**
     * 새로고침 클릭
     */
    fun refreshClick() {
        initCategoryInfo()
        refreshClickEvent()
    }

    /**
     * 전체 카테고리 API 관련 정보 초기화
     */
    fun initCategoryInfo() {
        initHospitalCategoryInfo()
        initPharmacyCategoryInfo()
        initOilCategoryInfo()
    }

    /**
     * 병원 카테고리 API 관련 정보 초기화
     */
    private fun initHospitalCategoryInfo() {
        currentHospitalPage = 1
        isHospitalPageEnd = false
    }

    /**
     * 약국 카테고리 API 관련 정보 초기화
     */
    private fun initPharmacyCategoryInfo() {
        currentPharmacyPage = 1
        isPharmacyPageEnd = false
    }

    /**
     * 주유 카테고리 API 관련 정보 초기화
     */
    private fun initOilCategoryInfo() {
        currentOilPage = 1
        isOilPageEnd = false
    }

    /**
     * 병원, 약국, 주유 카테고리 클릭
     */
    fun categoryClick(observableBoolean: ObservableBoolean) {
        observableBoolean.reverse()
        if (observableBoolean.get()) {
            if (!isHospitalEnabled.get() || isHospitalPageEnd) initHospitalCategoryInfo()
            if (!isPharmacyEnabled.get() || isPharmacyPageEnd) initPharmacyCategoryInfo()
            if (!isOilEnabled.get() || isOilPageEnd) initOilCategoryInfo()
        }
        categoryClickEvent()
    }

    /**
     * 더보기 클릭
     */
    fun moreClick() {
        isMore = true
        if (isHospitalEnabled.get()) currentHospitalPage++
        if (isPharmacyEnabled.get()) currentPharmacyPage++
        if (isOilEnabled.get()) currentOilPage++
        categoryClickEvent()
    }

    private fun ObservableBoolean.reverse() = set(!get())

}