package net.taehui.twilight.system

import com.google.protobuf.UnsafeByteOperations
import io.netty.bootstrap.Bootstrap
import io.netty.channel.ChannelHandlerContext
import io.netty.channel.ChannelInitializer
import io.netty.channel.EventLoopGroup
import io.netty.channel.epoll.EpollSocketChannel
import io.netty.channel.socket.SocketChannel
import io.netty.channel.socket.nio.NioSocketChannel
import io.netty.handler.codec.protobuf.ProtobufDecoder
import io.netty.handler.codec.protobuf.ProtobufEncoder
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender
import io.netty.handler.ssl.SslContextBuilder
import io.netty.handler.ssl.util.InsecureTrustManagerFactory
import net.taehui.twilight.HCDataHandler
import net.taehui.twilight.Logger
import net.taehui.twilight.awilight.AwilightAvatar
import org.apache.commons.lang3.SystemUtils
import org.apache.hc.client5.http.classic.methods.HttpGet
import org.apache.hc.client5.http.impl.classic.HttpClients
import java.io.IOException
import java.time.LocalDateTime
import java.util.concurrent.ConcurrentHashMap

object AwilightHandler : Logger {
    private val avatars = ConcurrentHashMap<ChannelHandlerContext, AwilightAvatar>()
    lateinit var eventLoopGroup: EventLoopGroup

    fun putAvatar(handler: ChannelHandlerContext, avatar: AwilightAvatar) {
        avatars[handler] = avatar
        logValueFuture {
            if (avatar.isBeginner) {
                try {
                    HttpClients.createDefault().use {
                        UnsafeByteOperations.unsafeWrap(
                            it.execute(
                                HttpGet("https://source.unsplash.com/random?twilight"),
                                HCDataHandler()
                            )
                        )
                    }
                } catch (e: IOException) {
                    logFault(e)
                    null
                }
            } else {
                null
            }
        }.thenAccept {
            val text = object {
                val qwilightName = avatar.qwilightName
                val hash = Configure.hash.randomOrNull()
                val date = ""
                val language = "ko-KR"
            }
            if (it != null) {
                avatar.send(EventOuterClass.Event.EventID.ESTABLISH, text, it)
            } else {
                avatar.send(EventOuterClass.Event.EventID.ESTABLISH, text)
            }
        }
    }

    fun loadAwilight() {
        avatars.values.forEach { it.loadAwilight() }
        logInfo("Loaded Awilight")
    }

    fun quitAvatar(handler: ChannelHandlerContext) {
        avatars.remove(handler)?.dispose()
    }

    fun setAwilightCount(awilightCount: Int) {
        WitSystem.wipeWit(this)
        if (awilightCount > 0) {
            WitSystem.handleLoop(
                this,
                LocalDateTime.now(),
                awilightCount
            ) {
                Bootstrap().group(eventLoopGroup)
                    .channel(if (SystemUtils.IS_OS_LINUX) EpollSocketChannel::class.java else NioSocketChannel::class.java)
                    .handler(object : ChannelInitializer<SocketChannel>() {
                        public override fun initChannel(ch: SocketChannel) {
                            ch.pipeline()
                                .addLast(
                                    SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE)
                                        .build()
                                        .newHandler(ch.alloc(), "taehui.ddns.net", 6101)
                                )
                                .addLast(ProtobufVarint32FrameDecoder())
                                .addLast(ProtobufDecoder(EventOuterClass.Event.getDefaultInstance()))
                                .addLast(ProtobufVarint32LengthFieldPrepender())
                                .addLast(ProtobufEncoder())
                                .addLast(AwilightAvatar())
                        }
                    }).connect("localhost", 6101)
            }
        } else {
            avatars.keys.stream().limit(-awilightCount.toLong())
                .forEach { it.close() }
        }
    }
}