package com.example.smart119.datas

import android.content.Context
import android.view.LayoutInflater
import android.widget.PopupWindow
import android.widget.Toast
import com.example.smart119.R
import com.example.smart119.interfaces.RetrofitClient
import com.example.smart119.views.FragmentHandler
import com.example.smart119.views.HospitalInfoPopup
import com.example.smart119.views.HospitalSearchPopup
import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

object HospitalSearch {
    private val savedHospList: MutableList<JsonObject> = mutableListOf()
    private var selectedHospitalIdx: Int = -1
    private var bUsedFilter: Boolean = false
    private var gpsAddress:String = "";
    private var hospDetail = mutableMapOf(
        "isTransfer" to false,
        "info" to mutableMapOf<String, Any>()
    )
    private val DEF_SEARCH:JsonObject = JsonObject().apply {
        addProperty("sidoName", "서울특별시")
        addProperty("sidoCode", "11")
    }
    private var prevLon:Double = 0.0;
    private var prevLat:Double = 0.0;
    private var prevTime:Long = 0;

    private var requestBody:JsonObject = JsonObject().apply {
        addProperty("bFilter", false)
        add("reqBody", JsonObject())
    }

    private lateinit var popupSearch: PopupWindow;

    private var sidoInfo:JsonObject = JsonObject().apply {
        addProperty("isLoaded", false)
    }
    private var gunGuInfo:JsonObject = JsonObject().apply {
        addProperty("isLoaded", false)
    }
    private var eubMyeonDongInfo:JsonObject = JsonObject().apply {
        addProperty("isLoaded", false)
    }
    private var gunGuNameList:MutableList<String> = mutableListOf()
    
    private var gunGuSelect:String = "군구선택";
    private var hospCatSelect:String = "병원분류명선택";
    private var prtSelect:String = "진료과목선택";

    private var addrFilterSave:JsonObject = JsonObject().apply {
        addProperty("si", "")
        addProperty("gu", "")
        addProperty("relate", "")
    }

    //true면 주소검색 사용, false면 위경도 검색 사용
    fun SET_SearchRequest(isAddress:Boolean, reqBody:JsonObject) {
        requestBody.addProperty("bFilter", isAddress)
        requestBody.add("reqBody", reqBody)
    }
    fun GET_SearchRequest():JsonObject {
        return requestBody;
    }

    fun isAddressSearch():Boolean {
        return requestBody.get("bFilter")?.asBoolean ?: false
    }

    fun setPrevGPSUpdate(lon:Double, lat:Double, time:Long) {
        prevLon = lon;
        prevLat = lat;
        prevTime = time;
        println("updated!!! ${prevLon}, ${prevLat}, ${prevTime}")
    }
    fun getPrevGPSInfo():JsonObject {
        return JsonObject().apply {
            addProperty("prevLon", prevLon)
            addProperty("prevLat", prevLat)
            addProperty("prevTime", prevTime)
        }
    }

    fun itemStructure(
        hpid: String = "", // 병원 아이디
        levelState: String = "", // lidar 레벨
        distance: String = "", // 거리
        city: String = "", // 시
        district: String = "", // 구
        tel: String = "", // 전화번호
        title: String = "", // 병원 이름
        lon: String = "", // 경도
        lat: String = "" // 위도
//        name: String = "",
//        address: String = "",
//        phoneNumber: String = "",
//        lidarState: String = ""
    ):JsonObject {
        return JsonObject().apply({
            addProperty("hpid", hpid)
            addProperty("levelState", levelState)
            addProperty("distance", distance)
            addProperty("city", city)
            addProperty("district", district)
            addProperty("tel", tel)
            addProperty("title", title)
            addProperty("lon", lon)
            addProperty("lat", lat)
        })
    }

    fun init_hospital_req(context:Context) {
        var sidoData = sidoInfo.getAsJsonObject("data");
        //비어있는 경우에만 요청하여 얻기
        if (sidoData == null || sidoData.entrySet().isEmpty()) {
            //1. 시 관련 콤보박스 먼저 얻기
            RetrofitClient.locInstance.getSidoList().enqueue(sidoResponse())
        }
    }

    fun get_gps_address():String {
        return gpsAddress
    }

    fun set_gps_update(address:String) {
        if(gpsAddress.isEmpty()) {
            gpsAddress = address
        }
    }
    
    fun set_selectGunGu(gunGu:String = "군구선택") {
        gunGuSelect = gunGu
    }
    fun get_selectGunGu():String {
        return gunGuSelect
    }

    fun set_selectHospCatAddress(hospCat:String = "병원분류명선택") {
        hospCatSelect = hospCat
    }
    fun get_selectHospCatAddress():String {
        return hospCatSelect
    }

    fun set_selectPrtAddress(prt:String = "진료과목선택") {
        prtSelect = prt
    }
    fun get_selectPrtAddress():String {
        return prtSelect
    }

    fun set_popup_search(searchPopup:PopupWindow) {
        popupSearch = searchPopup
    }
    fun get_popup_search(): PopupWindow {
        return popupSearch
    }

    fun req_gun_list(si:String) {
        RetrofitClient.locInstance.getSiGunGuList(JsonObject().apply {
            addProperty("code", get_si_code(si) ?: "")
        }).enqueue(siGunGuResponse())
    }

    private fun get_si_code(si:String): String {
        return sidoInfo["data"].asJsonObject["${si}"].asString
    }

    private fun _itemStructure_IDX(
        idx: Int = 0,
        hpid: String = "", // 병원 아이디
        levelState: String = "", // lidar 레벨
        distance: String = "", // 거리
        city: String = "", // 시
        district: String = "", // 구
        tel: String = "", // 전화번호
        title: String = "", // 병원 이름
        lon: String = "", // 경도
        lat: String = "" // 위도
    ):JsonObject {
        return JsonObject().apply({
            addProperty("idx", idx)
            addProperty("hpid", hpid)
            addProperty("levelState", levelState)
            addProperty("distance", distance)
            addProperty("city", city)
            addProperty("district", district)
            addProperty("tel", tel)
            addProperty("title", title)
            addProperty("lon", lon)
            addProperty("lat", lat)
        })
    }
    // JsonObject 추가
    fun addData(jsonObject: JsonObject) {
        savedHospList.add(jsonObject)
    }

    fun setSearchFilter(si:String, gu:String, relate:String) {
        addrFilterSave.addProperty("si", when(si) {"시도선택" -> "" else -> si })
        addrFilterSave.addProperty("gu", when(gu){"구군선택" -> "" else -> gu })
        addrFilterSave.addProperty("relate", relate)
    }

    fun setFiltered(bFiltered:Boolean) {
        bUsedFilter = bFiltered;
    }

    fun getSearchInfo():JsonObject {
        return addrFilterSave;
    }

    fun getIsFiltered():Boolean {
        return bUsedFilter
    }

    fun addDataHospitalItems(hospList:List<JsonObject>) {
        var idx = 0;
        hospList.forEach{
            hosp ->
            var rebuild = _itemStructure_IDX(
                idx++,
                hosp["hpid"].toString().trim('"'),
                hosp["levelState"].toString().trim('"'),
                hosp["distance"].toString().trim('"'),
                hosp["city"].toString().trim('"'),
                hosp["district"].toString().trim('"'),
                hosp["tel"].toString().trim('"'),
                hosp["title"].toString().trim('"'),
                hosp["lon"].toString().trim('"'),
                hosp["lat"].toString().trim('"')
            )
            savedHospList.add(rebuild)
        }
//        println(savedHospList);
    }

    // 인덱스로 JsonObject 가져오기
    fun getData(index: Int): JsonObject? {
        return if (index in savedHospList.indices) savedHospList[index] else null
    }

    fun setIdx(idx:Int) {
        selectedHospitalIdx = idx
    }

    fun getSelectedData(): JsonObject? {
        if (selectedHospitalIdx != -1) {
//            var returnData = JsonObject().apply {  }
            val returnData = savedHospList.getOrNull(selectedHospitalIdx)
            return returnData
        }
        else return null
    }

    //region hospital detail용 함수
    fun getHospitalID():String {
        if (selectedHospitalIdx != -1) {
            val returnData = savedHospList.getOrNull(selectedHospitalIdx)
            return returnData?.get("hpid")?.asString ?: "";
        }
        else return ""
    }
    fun setHospitalDetail(info:JsonObject) {
        hospDetail["info"] = info;
    }
    fun getHospitalDetail():Any? {
        return hospDetail["info"]
    }
    //endregion

    fun getAllData(withIndex:Boolean = false):List<List<String>> {
        val setDataList:MutableList<List<String>> = mutableListOf()
        savedHospList.forEach {
            json ->
            if(withIndex) {
                val address =
                    json["city"].toString().replace("\"", "") + " " +
                            json["district"].toString().replace("\"", "")
                setDataList.apply {
                    add(
                        listOf(
                            json["idx"].toString().replace("\"", ""),
                            json["title"].toString().replace("\"", ""),
                            address,
                            json["tel"].toString().replace("\"", ""),
                            json["levelState"].toString().replace("\"", ""),
                            json["distance"].toString().replace("\"", "") + "km"
                        )
                    )
                }
            }
            else {
                val address =
                    json["city"].toString().replace("\"", "") + " " +
                            json["district"].toString().replace("\"", "")
                setDataList.apply {
                    add(
                        listOf(
                            json["title"].toString().replace("\"", ""),
                            address,
                            json["tel"].toString().replace("\"", ""),
                            json["levelState"].toString().replace("\"", ""),
                            json["distance"].toString().replace("\"", "") + "km"
                        )
                    )
                }
            }
        }
        return setDataList
    }

    fun clearAllData() {
        selectedHospitalIdx = 0;
        savedHospList.clear()
    }

    private fun sidoResponse(): Callback<JsonObject> {
        return object : Callback<JsonObject> {
            override fun onResponse(call: Call<JsonObject>, response: Response<JsonObject>) {
                if (response.isSuccessful) {
                    val jsonObject = response.body();
                    var dataSet = JsonObject()
//                    println("sido response success ${jsonObject}");
                    if (jsonObject != null) {
                        val resDatas = jsonObject["resData"].asJsonArray;
                        resDatas.forEach { data ->
                            val _sicode = data.asJsonObject["sidoCode"].asString
                            val _siname = data.asJsonObject["sidoName"].asString
                            dataSet.addProperty(_siname, _sicode)
                        }
                    }
                    //loaded true, data set
                    sidoInfo.addProperty("isLoaded", true)
                    sidoInfo.add("data", dataSet)

                    //#region 현재 서울시를 중점으로 하기 때문에, 기본 코드 API요청
                    req_gun_list(DEF_SEARCH["sidoName"].asString)
                    //#endregion

                } else {
                    println("sido response but fail");
                    sidoDeafult()
                }
            }

            override fun onFailure(call: Call<JsonObject>, t: Throwable) {
                println("sido response fail ${t.message}");
                sidoDeafult()
            }
        }
    }
    private fun sidoDeafult() {

        var dataSet = JsonObject()
        val default_si = DEF_SEARCH["sidoName"].asString;
        val default_siCode = DEF_SEARCH["sidoCode"].asString;
        dataSet.addProperty(default_si, default_siCode)

        sidoInfo.addProperty("isLoaded", false)
        sidoInfo.add("data", dataSet)

        req_gun_list(default_si)
    }
    fun GET_SIDO_DEFAULT_NAME():String {
        return DEF_SEARCH["sidoName"].asString
    }
    fun GET_SIDO_DEFAULT_CODE():String {
        return DEF_SEARCH["sidoCode"].asString
    }

    fun getSidoList():List<String> {
        var returnList: List<String> = mutableListOf()
        if (sidoInfo["isLoaded"].asBoolean) {
            var sidoJsonObject = sidoInfo.getAsJsonObject("data")
            returnList = sidoJsonObject.entrySet().map { it.key }
        }
        return returnList;
    }
    fun getGunGuNameList():MutableList<String> {
        return gunGuNameList.toMutableList();
    }

    private fun siGunGuResponse(): Callback<JsonObject> {
        return object : Callback<JsonObject> {
            override fun onResponse(call: Call<JsonObject>, response: Response<JsonObject>) {
                if (response.isSuccessful) {
                    val jsonObject = response.body();
                    var dataSet = JsonObject();
//                    println("sido response success ${jsonObject}");
                    if (jsonObject != null) {
                        val resDatas = jsonObject["resData"].asJsonArray;
                        resDatas.forEach { data ->
                            val _guguncode = data.asJsonObject["code"].asString
                            val _gugunName = data.asJsonObject["name"].asString
                            dataSet.addProperty(_gugunName, _guguncode)
                            gunGuNameList.add(_gugunName)
                        }
                    }
                    //loaded true, data set

                    gunGuInfo.addProperty("isLoaded", true)
                    gunGuInfo.add("data", dataSet)

                    //세팅 구군 리스트
//                    var hsfView = FragmentHandler.getView("HospitalSearchFragment")
//                    if (hsfView != null) {
//                        nameList.add(0, "구군선택")
//                        HospitalSearchPopup.set_POPUP_GUGUN_COMBO(popupSearch, hsfView.context, nameList)
//                    }
                } else {
                    println("gugun response but fail");
                    SEOUL_DEFAULT_GUNGU()
                }
            }

            override fun onFailure(call: Call<JsonObject>, t: Throwable) {
                println("gugun response fail ${t.message}");
                SEOUL_DEFAULT_GUNGU()
            }
        }
    }


    private fun siEubMyeonDongResponse(): Callback<JsonObject> {
        return object : Callback<JsonObject> {
            override fun onResponse(call: Call<JsonObject>, response: Response<JsonObject>) {
                if (response.isSuccessful) {
                } else {
                }
            }

            override fun onFailure(call: Call<JsonObject>, t: Throwable) {
            }
        }
    }

    private fun SEOUL_DEFAULT_GUNGU() {
        var dataSet = JsonObject();
        var nameList:MutableList<String> = mutableListOf()

        dataSet.addProperty("11680","강남구")
        dataSet.addProperty("11740","강동구")
        dataSet.addProperty("11305","강북구")
        dataSet.addProperty("11500","강서구")
        dataSet.addProperty("11620","관악구")
        dataSet.addProperty("11215","광진구")
        dataSet.addProperty("11530","구로구")
        dataSet.addProperty("11545","금천구")
        dataSet.addProperty("11350","노원구")
        dataSet.addProperty("11320","도봉구")
        dataSet.addProperty("11230","동대문구")
        dataSet.addProperty("11590","동작구")
        dataSet.addProperty("11440","마포구")
        dataSet.addProperty("11410","서대문구")
        dataSet.addProperty("11650","서초구")
        dataSet.addProperty("11200","성동구")
        dataSet.addProperty("11290","성북구")
        dataSet.addProperty("11710","송파구")
        dataSet.addProperty("11470","양천구")
        dataSet.addProperty("11560","영등포구")
        dataSet.addProperty("11170","용산구")
        dataSet.addProperty("11380","은평구")
        dataSet.addProperty("11110","종로구")
        dataSet.addProperty("11140","중구")
        dataSet.addProperty("11260","중랑구")

        for((key, value) in dataSet.entrySet()) {
            gunGuNameList.add(value.asString)
        }

        gunGuInfo.addProperty("isLoaded", false)
        gunGuInfo.add("data", dataSet)

        println();
    }

}