package kr.lunaticbum.back.lun.controllers

import com.drew.imaging.ImageMetadataReader
import com.drew.metadata.Metadata
import com.google.gson.Gson
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import kr.lunaticbum.back.lun.configs.GlobalEnvironment
import kr.lunaticbum.back.lun.configs.GlobalEnvironment.Companion.ApiKeyWordKey
import kr.lunaticbum.back.lun.configs.GlobalEnvironment.Companion.EncType11
import kr.lunaticbum.back.lun.configs.GlobalEnvironment.Companion.EncTypeKey
import kr.lunaticbum.back.lun.model.*
import kr.lunaticbum.back.lun.service.JwtService
import kr.lunaticbum.back.lun.utils.LogService
import kr.lunaticbum.back.lun.utils.getFileExtension
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.core.io.Resource
import org.springframework.core.io.UrlResource
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
import org.springframework.web.multipart.MultipartFile
import org.springframework.web.reactive.function.client.WebClient
import java.io.*
import java.net.URLDecoder
import java.text.SimpleDateFormat
import java.util.*


@RestController
@RequestMapping("/blog")
class BlogController() {
    companion object {
        val TEMPTOKEN = "TEMP_TOKEN_VIBUM"
    }
    @Autowired
    lateinit var globalEvv : GlobalEnvironment

    @Autowired
    private lateinit var locationLogService: LocationLogService

    @Autowired
    private lateinit var postManageg: PostManageg

    @Autowired
    lateinit var logService: LogService
    val WRITE_PERMISSION_KEY = "PERMISSION"
    @GetMapping("write/{token}","write")
    fun writ(@PathVariable token : String? ) : ResultMV{
        val vm = ResultMV("content/blog/write")
        if (token.equals(TEMPTOKEN)) {
            vm.modelMap.put(WRITE_PERMISSION_KEY,"OK")
            vm.modelMap.put(EncTypeKey, EncType11)
            vm.modelMap.put(ApiKeyWordKey,"WRITE")
            vm.modelMap.put("title","회원이 들어는 구나~!!")
            vm.modelMap.put("defaultTitle","무제(無題) (Untitled, ${SimpleDateFormat("yyyy-MM-dd HH:mm").format(Date())})")
        } else {
            vm.modelMap.put(WRITE_PERMISSION_KEY,"NO")
        }
//        when(System.currentTimeMillis() % 5L) {
//            0L -> vm.modelMap.put(EncTypeKey,"T4")
//            1L ->    vm.modelMap.put(EncTypeKey,"T3")
//            2L ->    vm.modelMap.put(EncTypeKey,"T2")
//            else -> vm.modelMap.put(EncTypeKey,"T0")
//        }

        return vm
    }

    @PostMapping("post.ajax")
    fun post(httpServletRequest: HttpServletRequest, @RequestBody jsonString: String) : ResponseEntity<ResponceResult> {
        logService.log(httpServletRequest.requestURI)
        logService.log(jsonString)
        var lResultCode = 0
        var lResultMsg = "Suscces"
        val decodedBytes: ByteArray = Base64.getDecoder().decode(jsonString)
        String(decodedBytes).let {
            Gson().fromJson<RequestModel>(it, RequestModel::class.java)?.let { model ->
                logService.log(Gson().toJson(model))
                model.data?.let {   jsonString ->
                    try {
                        val reqString = jsonString.split(GlobalEnvironment.padding(model.getKeyword()))
                        val nb = arrayListOf<String>()
                        val na = arrayListOf<String>()
                        reqString[0].replace(GlobalEnvironment.padding(model.getKeyword()),"").split("").toList().let { na.addAll(it) }
                        reqString[1].replace(GlobalEnvironment.padding(model.getKeyword()),"").split("").toList().let { nb.addAll(it) }
                        var max = nb.size + na.size
                        var fullData = arrayListOf<String>()
                        for (idx in 0..max) { if (idx % 2 == 0) { if (nb.size > 0) { fullData.add(nb.removeLast()) } } else { if (na.size > 0) { fullData.add(na.removeLast()) } } }
                        logService.log(fullData.joinToString(""))
                        var target = Gson().fromJson(fullData.joinToString(""), Post::class.java) ?: Post()
                        if (target.writeTime < 1L) {
                            target.id = null
                            target.writeTime = System.currentTimeMillis()
                        } else {
                            logService.log("target.writeTime >>> ${target.writeTime}")
                            target.modifyTime = System.currentTimeMillis()
                            postManageg.save(target)
                            target = Gson().fromJson(fullData.joinToString(""), Post::class.java) ?: Post()
                            target.originId = target.id
                            target.id = null
                        }
                        var postMono = postManageg.save(target)
                        if (postMono != null) {
                            lResultMsg = "save post"
                            lResultCode = 0
                        } else {
                            lResultMsg = "not founding user[can't find same id,email.. ]"
                            lResultCode = 7100
                        }
                    } catch (e: Exception) {
                        e.printStackTrace()
                        lResultMsg = "unknown exception"
                        lResultCode = 7999
                    }
                }
            }
        }
        val responce = ResponseEntity.ok().headers {
        }.contentType(MediaType.APPLICATION_JSON).body(ResponceResult().apply {
            this.resultCode = lResultCode
            this.resultMsg = lResultMsg
        })
        return responce
    }

    @GetMapping("viewer/{postId}")
    fun viewer(@PathVariable postId : String) : ResultMV{
        val vm = ResultMV("content/blog/viewer")
        postManageg.getPost(postId).block().apply {
            this?.title = URLDecoder.decode(this?.title)
            this?.content = URLDecoder.decode(this?.content)
            vm.modelMap.put("srcPost",this)
        }
        return vm
    }

    @Autowired
    lateinit var jwtService : JwtService

    @GetMapping("modify")
    fun modify(httpServletRequest: HttpServletRequest, @RequestParam("token") token : String?) : ResultMV{
        logService.log("incoming modify")
        val vm = ResultMV("content/blog/modify")
        vm.modelMap.put(WRITE_PERMISSION_KEY,"NO")
        httpServletRequest.getSession(true)?.let { session ->
            (session.getAttribute(WRITE_PERMISSION_KEY) as? Boolean)?.let {
                postManageg.find20()?.apply {
                    forEach {
                        it.title = URLDecoder.decode(it.title)
                        val content = URLDecoder.decode(it.content)
                        it.content = if (content.length > 50) content.substring(0,150) else content
                    }
                    vm.modelMap.put("chunkedPosts", this.chunked(3))
                }
                vm.modelMap.put(WRITE_PERMISSION_KEY,"OK")
                vm.modelMap.put("path","editor/")
                vm.modelMap.put("SK",token)
            }
        }
        vm.modelMap.put("rowKey","chunkedPosts_")
        return vm
    }

    @GetMapping("editor/{postId}")
    fun editor(@PathVariable postId : String) : ResultMV{
        val vm = ResultMV("content/blog/editor")
        postManageg.getPost(postId).block().apply {
            this?.title = URLDecoder.decode(this?.title)
            this?.content = URLDecoder.decode(this?.content)
            vm.modelMap.put("srcPost",this)
        }
        return vm
    }


    @GetMapping("recent")
    fun recent() : ResultMV{
        val vm = ResultMV("content/blog/viewer")
        locationLogService.find10().forEach {
            logService.log(Gson().toJson(it))
        }
        locationLogService.getLocationLog()?.let {
            try {
                val client0 = WebClient.create()
                val result = client0.get()
                    .uri("http://api.weatherapi.com/v1/current.json?key=${globalEvv.weatherApiKey}&q=${it.mLatitude},${it.mLongitude}&aqi=no")
                    .retrieve()
                    .bodyToMono(String::class.java)
                    .block() ?: "FAIL"
                Gson().fromJson(result, CurrentWeather::class.java)?.let { sss ->
                    logService.log("지역:${sss.location?.name}\n날씨:${sss.current?.condition?.text}\n온도:${sss.current?.temp_c}\n습도:${sss.current?.humidity}\n" +
                            "체감온도:${sss.current?.feelslike_c}\nhttps://www.accuweather.com/ko/search-locations?query=${it.mLatitude},${it.mLongitude}")
                }
            }
            catch (e : Exception) {

            }
        }
        return vm
    }


    @Value("\${image.upload.path}")
    private val uploadPath: String? = null

    @Value("\${resource.handler}")
    private val resourceHandler: String? = null


    @ResponseBody
    @GetMapping("post/images/{fileName}")
    fun getImage(@PathVariable fileName : String) : Resource {
        val imgUploadPath = ("file:" +uploadPath + File.separator + fileName)
        return UrlResource.from(imgUploadPath)
    }

    @PostMapping("post/imageUpload")
    fun postImage(@RequestPart("file") upload: MultipartFile, res: HttpServletResponse, req: HttpServletRequest) : ResponseEntity<FileSaveResult>  {
        var lResultCode = 0
        var lResultMsg = "Suscces"
        var out: OutputStream? = null
        var printWriter: PrintWriter? = null
        var targetFile : File? = null
        logService.log("imgUploadPath ${upload.originalFilename}")
        res.characterEncoding = "utf-8"
        res.contentType = "text/html;charset=utf-8"
        var uuid = UUID.randomUUID()
        val extension: String = getFileExtension(upload.originalFilename) ?: ""
        try {

            logService.log("imgUploadPath ${uuid.toString()}")

            val bytes = upload.bytes

            var f = File(uploadPath)
//            logService.log("imgUploadPath ${f.parentFile.parentFile.parentFile.parentFile.absoluteFile}")
//            logService.log("imgUploadPath ${f.parentFile.parentFile.parentFile.absoluteFile}")
//            logService.log("imgUploadPath ${f.parentFile.parentFile.absoluteFile}")
//            logService.log("imgUploadPath ${f.parentFile.absoluteFile}")
            logService.log("imgUploadPath ${f.exists()}")
            logService.log("imgUploadPath ${f.absolutePath}")
            if (f.exists() == false) f.mkdirs()
            // 실제 이미지 저장 경로
            val imgUploadPath = (uploadPath + File.separator + uuid).toString() + "." + extension
            logService.log("imgUploadPath $imgUploadPath")
            targetFile = File(imgUploadPath)
            if(targetFile.parentFile.exists() == false)targetFile.parentFile.mkdirs()

            // 이미지 저장
            out = FileOutputStream(imgUploadPath)
            out.write(bytes)
            out.flush()

            // ckEditor 로 전송
//            printWriter = res.writer
//            val callback = req.getParameter("CKEditorFuncNum")
//            val fileUrl = "/blog/post/image/$uuid.$extension"

//            printWriter.println(
//                ("<script type='text/javascript'>"
//                        + "window.parent.CKEDITOR.tools.callFunction("
//                        + callback + ",'" + fileUrl + "','이미지를 업로드하였습니다.')"
//                        + "</script>")
//            )
//
//            printWriter.flush()
            logService.log("imgUploadPath $imgUploadPath")
            logService.log("imgUploadPath ${File(imgUploadPath).exists()}")
            val metadata: Metadata? = ImageMetadataReader.readMetadata(File(imgUploadPath))
            metadata?.let {
                it.directories?.forEach { directory ->
                    logService.log(directory.name)
                    logService.log(directory.tags.map { tag -> logService.log("tag.tagName >>> ${tag.tagName} || tag.description  ${tag.description}")}.joinToString(" \n"))
                }
            }
        } catch (e: IOException) {
            e.printStackTrace()
        } finally {
            try {
                out?.close()
                printWriter?.close()
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
        val responce = ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(FileSaveResult().apply {

            this.resultCode = lResultCode
            this.resultMsg = lResultMsg
            this.fileName = "$uuid.$extension"
        })
        return responce
    }
}