package com.lemonhc.mplus.adapter

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Environment
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import com.lemonhc.mplus.MPlusConstants.DOMAIN_NAME
import com.lemonhc.mplus.framework.constant.FrameworkConstant
import com.lemonhc.mplus.framework.task.ApiClient
import com.lemonhc.mplus.framework.util.kotlinExtension.format
import com.lemonhc.mplus.framework.util.kotlinExtension.position
import com.lemonhc.mplus.framework.util.kotlinExtension.toBase64
import com.lemonhc.mplus.mcare_plus.R
import com.lemonhc.mplus.mcare_plus.activity.GallaryActivity
import com.lemonhc.mplus.mcare_plus.activity.PhotoActivity
import com.lemonhc.mplus.mcare_plus.activity.PhotoDetailActivity
import com.lemonhc.mplus.model.Photo
import com.lemonhc.mplus.model.delete
import com.lemonhc.mplus.model.update
import org.json.JSONArray
import org.json.JSONObject
import java.io.File
import java.io.IOException
import java.util.*
import kotlin.collections.ArrayList

/**
 * Created by Geoffrey Koros on 9/4/2015.
 */
class PhotoListViewAdapter(context: Context): ArrayAdapter<Any>(context, textViewResourceId) {
    companion object {
        const val textViewResourceId: Int = R.layout.list_item
    }

    // 원본 이미지
    open var photoPath = "${Environment.getExternalStorageDirectory()}/kunkuk"
    // 썸네일 이미지
    open var thumbPath = "${Environment.getExternalStorageDirectory()}/kunkuk/thumb"

    // 전체아이템
    lateinit var items: List<Pair<String, MutableList<Photo>>>

    // 헤더 포지션
    var sectionHeaderPosition: MutableSet<Pair<String, Int>> = HashSet()

    private val layoutInflater: LayoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
    private val numberOfCols: Int = if(FrameworkConstant.isTablet(context as Activity)) 6 else 3

    // 선택된 아이템 리스트
    var checkedItems: MutableSet<Pair<Int, Int>> = HashSet()
    // 전체선택 여부
    var checkFlag = false
    // 전체 환자 선택 여부
    var allPatientFlag: Boolean = false
    // 실패한 아이템 카운트
    private var failCount = 0
    // 성공한 아이템 카운트
    private var successCount = 0

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
        val view: View
        if (isHeaderPosition(position)) { // 헤더인지 체크
            view = layoutInflater.inflate(R.layout.grid_header_view, parent, false)
            val headerText = view.findViewById(R.id.headerText) as TextView
            headerText.text = getHeaderForSection(position) ?: ""
        } else { // 아이템일 경우
            view = layoutInflater.inflate(R.layout.row_item, parent, false)
            //아이템이 널일경우 중단
            val list = getItem(position) ?: return view

            for (i: Int in list.indices) {
                val item: Photo  = list[i]
                val grid: FrameLayout = layoutInflater.inflate(R.layout.grid_item, view as ViewGroup, false) as FrameLayout
                grid.position = Pair(position, i)

                // 클릭리스너
                grid.setOnClickListener(itemClicked())
                grid.setOnLongClickListener(itemLongClicked())

                val imageView: ImageView = grid.findViewWithTag("image") as ImageView
                val checkView: ImageView = grid.findViewById(R.id.check)
                val sendView: FrameLayout = grid.findViewById(R.id.send_view)

                // 이미지 세팅
                if (File("$thumbPath/${item.file}").isFile) {
                    val bitmap: Bitmap = BitmapFactory.decodeFile("$thumbPath/${item.file}")
                    imageView.setImageBitmap(bitmap)
                } else {
                    checkView.setImageResource(R.drawable.gall_chk_active)
                    checkedItems.add(Pair(position, i))
                    deleteItem()
                    continue
                }

                // 선택여부
                if (checkedItems.contains(Pair(position, i))) {
                    checkView.setImageResource(R.drawable.gall_chk_active)
                } else {
                    checkView.setImageResource(R.drawable.gall_chk_default)
                }

                // 이미 업로드한 파일인지 여부
                if (item.isSended) {
                    sendView.setBackgroundResource(R.drawable.border)
                } else {
                    sendView.background = null
                }
                view.addView(grid)
            }

            // 남은 빈공간이 있을경우 빈 데이타를 넣어준다
            val count: Int = numberOfCols - list.count()
            for (i: Int in 0 until count) {
                val grid: FrameLayout = layoutInflater.inflate(R.layout.grid_item, view as ViewGroup, false) as FrameLayout
                grid.visibility = View.INVISIBLE
                view.addView(grid)
            }
        }
        return view
    }

    override fun getCount(): Int {
        // 전체개수
        var totalItems = 0
        // 아이템이 없을경우 중단
        if (items.count() == 0) {
            return 0
        }

        sectionHeaderPosition = HashSet()

        // 각 키별로 아이템의 라인 수를 구한다 아이템크기 / 최대 갯수
        for (item: Pair<String, MutableList<Photo>> in items) {
            // 리스트 아이템이 한 줄 최대갯수가 넘어가면 로우 증가
            val rows:Int = item.let {
                if (it.second.count() % numberOfCols == 0) {
                    return@let it.second.count() / numberOfCols
                } else {
                    return@let it.second.count() / numberOfCols + 1
                }
            }

            // 아이템이 있을경우
            if (rows > 0) {
                sectionHeaderPosition.add(Pair(item.first, totalItems))
                totalItems += 1 // header view takes up one position
            }
            totalItems += rows
        }
        return totalItems
    }

    override fun getItem(position: Int): MutableList<Photo>? {
        // 헤더일경우 리턴
        if (isHeaderPosition(position)) {
            return null
        }

        // 아이템 위치를 찾아 키를 받아온다 null일수 있음
        val key: String = getItemKeyAtPosition(position) ?: ""

        // 전체 아이템을 가져온다
        val values: MutableList<Photo> = items.filter {
            it.first == key
        }.map {
            it.second
        }.firstOrNull() ?: return null

        // 해당 아이템의 헤더 포지션을 가져온다
        var headerPosition: Int = getHeaderPosition(key)
        // 현재위치가 헤더에서 얼만큼 떨어져있는지 계산후
        var step: Int = position - headerPosition
        // 헤더의 값을 빼준다
        var stepLeaveHeader: Int = (step - 1) * numberOfCols
        // 한줄의 최대 값을 구한후
        var stepToNextRow: Int = stepLeaveHeader + numberOfCols

        var returns: MutableList<Photo> = ArrayList()
        for (i: Int in stepLeaveHeader until stepToNextRow) {
            // 만일 오버플로우하면 멈춘다
            if (i > values.count() - 1) {
                break
            }
            returns.add(values[i])
        }
        return returns
    }

    private fun getHeaderPosition(key: String): Int {
        return sectionHeaderPosition.filter {
            it.first == key
        }.map {
            it.second
        }.firstOrNull() ?: 0
    }

    /**
     * 아이템 위치를 찾아 키를 받아온다 null일수 있음
     */
    private fun getItemKeyAtPosition(position: Int): String? {
        val max: Pair<String, Int>? = sectionHeaderPosition.filter {
            it.second < position
        }.maxBy {
            it.second
        }
        return max?.first
    }

    /**
     * 헤더인지 여부 체크
     */
    private fun isHeaderPosition(position: Int): Boolean {
        val count: Int = sectionHeaderPosition.filter {
            it.second == position
        }.count()
        return count > 0
    }

    /**
     * 헤더키를 얻어온다 null일수 있음
     */
    private fun getHeaderForSection(section: Int): String? {
        return sectionHeaderPosition.filter {
            it.second == section
        }.map {
            it.first
        }.firstOrNull()
    }

    fun allCheck() {
        for (i: Int in 0 until this.count) {
            // 해당하는 아이템이 없으면 중단
            val list: MutableList<Photo> = getItem(i) ?: continue
            for (j: Int in list.indices) {
                // 전체선택일경우
                if (checkFlag) {
                    checkedItems.add(Pair(i, j))
                } else {
                    checkedItems = HashSet()
                    this.notifyDataSetChanged()
                    return
                }
            }
        }
        this.notifyDataSetChanged()
    }


    private var uploadCount: Int = 0
    fun sendItem() {
        var items = ArrayList<Photo>()
        successCount = 0
        failCount = 0
        // 선택된 아이템을 찾는다
        for (pair: Pair<Int, Int> in checkedItems) {
            val list: MutableList<Photo> = getItem(pair.first) ?: continue
            val item: Photo = list[pair.second]

            if (item.isSended) {
                continue
            }
            if (!File("$photoPath/${item.file}").isFile) {
                Toast.makeText(context, "${item.file} 파일을 찾을수 없습니다.", Toast.LENGTH_SHORT).show()
                continue
            }
            //item.isSended = true
            //uploadItem(item)
            items.add(item)
            this.checkedItems = this.checkedItems.filter { it != pair }.toMutableSet()
        }

        uploadCount = items.size
        for (item: Photo in items) {
            uploadItem(item)
        }

        var json: JSONObject = JSONObject().apply {
            put("success", successCount)
            put("fail", failCount)
        }

        PhotoActivity.callBack(json)
        this.notifyDataSetInvalidated()
    }

    private fun uploadItem(item: Photo) {
        val param: MutableList<Pair<String, Any?>> = mutableListOf<Pair<String, Any?>>().apply {
            add("hospitalCd" to item.user.hospitalCD)
            add("userId" to item.user.userId)
            add("patientId" to item.user.patientId)
            add("deptCd" to item.user.deptCd)
            add("doctorId" to item.user.doctorId)
            add("searchCls" to item.user.treatCls)
            add("thumbnail" to "")
            add("excutionDtTm" to Date().format("yyyy-MM-dd hh:mm:ss"))
            add("visitDt" to item.user.visitDt)
            add("image" to File("$photoPath/${item.file}").toBase64())
        }

        val url = "$DOMAIN_NAME${item.user.serviceUrl}"
        ApiClient(url, param, header_param = mapOf("Content-Type" to "application/json"))
                .encType(ApiClient.ENC_Type.Json)
                .connect {
                    val json: JSONObject = it ?: run {
                        // json 값이 실제로 들어있는지 체크하는 로직 추가
                        Toast.makeText(context, "서버와 통신이 원활하지 않습니다.", Toast.LENGTH_LONG).show()
                        return@connect
                    }
                    // 성공일시
                    val result: JSONArray = json.getJSONArray("result")
                    val returnCd: String? = result.getJSONObject(0).get("returnCd") as? String

                    if (returnCd == "0000") {
                        item.isSended = true
                        successCount += 1
                        item.update()
                    } else {
                        failCount += 1
                    }
                    uploadItemEnd()
                }
    }

    private fun uploadItemEnd() {
        if (uploadCount != (successCount + failCount)) {
            return
        }
        if (failCount > 0) {
            Toast.makeText(context, "${failCount}건 전송에 실패하였습니다.", Toast.LENGTH_SHORT).show()
        } else {
            Toast.makeText(context, "${successCount}건 전송이 완료되었습니다.", Toast.LENGTH_SHORT).show()
        }
        notifyDataSetChanged()
    }

    /**
     * 선택된 이미지 삭제
     */
    fun deleteItem() {
        // 선택된 아이템을 찾는다
        for (pair:Pair<Int, Int> in checkedItems) {
            val list: MutableList<Photo> = getItem(pair.first) ?: continue
            val item: Photo = list[pair.second]
            item.delete()
            // 실제 경로의 파일을 삭제처리
            deleteOriginAndThumbnails(item.file)
            this.checkedItems = this.checkedItems.filter { it != pair }.toMutableSet()
        }
        GallaryActivity.reloadTable.value = true
    }

    private fun deleteOriginAndThumbnails(filePath: String) {
        try {
            //원본 파일 삭제
            val origin = File("$photoPath/$filePath")
            origin.delete()
            //썸네일 파일 삭제
            val thumb = File("$thumbPath/$filePath")
            thumb.delete()
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

    /**
     * 아이템 개별 체크 전체선택 flag와 개별로 동작
     */
    private fun itemClicked(): View.OnClickListener {
        return View.OnClickListener {
            val checkView: ImageView = it.findViewById(R.id.check)
            val position: Pair<Int, Int> = it.position
            it.isSelected = !it.isSelected
            // 아이템이 선택되면 check array에 추가한다
            if (it.isSelected) {
                checkView.setImageResource(R.drawable.gall_chk_active)
                checkedItems.add(position)
            } else {
                checkView.setImageResource(R.drawable.gall_chk_default)
                checkedItems.remove(position)
            }
        }
    }

    /**
     * 환부 이미지 롱 클릭시
     */
    private fun itemLongClicked(): View.OnLongClickListener {
        return View.OnLongClickListener {
            detailAction(it)
            //클릭처리 안함
            true
        }
    }

    /**
     * 파일 확대보기
     */
    private fun detailAction(v: View) {
        val position: Pair<Int, Int> = v.position

        // 해당하는 아이템이 없으면 중단
        val list: MutableList<Photo> = getItem(position.first) ?: return
        val item: Photo = list[position.second]

        if (!File("$photoPath/${item.file}").isFile) {
            Toast.makeText(context, "원본 ${item.file} 파일을 찾을수 없습니다.", Toast.LENGTH_LONG).show()
            return
        }

        PhotoDetailActivity.item = item
        PhotoDetailActivity.callBack = {
            notifyDataSetChanged()
        }

        // 실제 파일 경로를 인텐트로 넘겨준다
        val intent = Intent(v.context, PhotoDetailActivity::class.java)
        intent.putExtra("filePath", "$photoPath/${item.file}")
        v.context.startActivity(intent)
    }

//    fun deleteAction(v:View){
//        val position = v.position
//
//        //해당하는 아이템이 없으면 중단
//        val list = getItem(position.first) ?: return
//        val item = list[position.second]
//
//        item.delete()
//        //실제 경로의 파일을 삭제처리
//        deleteOriginAndThumbnails(item.file)
//
//        //새로운 리스트를 반환
//        items = items.map {
//            val pair = Pair(
//                    it.first,
//                    it.second.filterNot {
//                        return@filterNot it.file == item.file
//                    }.toMutableList()
//            )
//            return@map pair
//        }
//
//        this.checkedItems = this.checkedItems.filter { it != position }.toMutableSet()
//
//
//        //실제 줄바꿈이 일어나므로 dataSetChange 호출
//        notifyDataSetChanged()
//    }

    //보낸파일 재전송
//    fun reUploadAction(v:View){
//        val position = v.position
//
//        //해당하는 아이템이 없으면 중단
//        val list = getItem(position.first) ?: return
//        val item = list[position.second]
//        uploadItem(item)
//
//    }

}
