package com.its.vms.xnettcp.vms.process;

import com.its.vms.domain.NET;
import com.its.vms.dto.TbVmsCtlrDto;
import com.its.vms.xnettcp.vms.protocol.dto.VmsReqControlDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;

import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;

@Slf4j
@RequiredArgsConstructor
public class TcpServerSendDataProcess {

    private final TbVmsCtlrDto vmsCtlr;

    private final LinkedBlockingQueue<TcpServerSendData> reqCommandBlockingQueue = new LinkedBlockingQueue<>(100);
    private final ThreadPoolExecutor taskExecutor = (ThreadPoolExecutor)Executors.newFixedThreadPool(1);

    public void run() {
        log.info("TcpServerReqDataProcess[{}].run: Start.", this.vmsCtlr.getCtlrNmbr());
        this.taskExecutor.execute(() -> {
            boolean isRunning = true;
            while (isRunning) {
                try {
                    TcpServerSendData reqData = this.reqCommandBlockingQueue.take();
                    process(reqData);
                }
                catch (InterruptedException e) {
                    log.error("TcpServerReqDataProcess.Task: Exception: {}", e.getMessage(), e);
                    Thread.currentThread().interrupt();
                    isRunning = false;
                }
            }
        });
    }

    public void process(TcpServerSendData data) {

        MDC.put("id", this.vmsCtlr.getLogKey());

        boolean isConnected = (this.vmsCtlr.getNetState() > NET.CLOSED && this.vmsCtlr.getChannel() != null);
        boolean isRequested = false;
        log.info("TcpServerReqDataProcess[{}].process: command({}), connected({}), Elapsed: {} ms.", this.vmsCtlr.getCtlrNmbr(), data.getCommand(), isConnected, data.elapsed());

        if (isConnected) {
            try {
                switch (data.getCommand()) {
                    case TcpServerSendData.DATA_RES_DEVICE_ID:
                        // 디바이스 인증요청에 대한 응답
                        // 디바이스 정보가 일치 하지 않으면 네트워크 연결을 종료한다.
                        break;
                    case TcpServerSendData.DATA_REQ_CONTROL:
                        VmsReqControlDto control = (VmsReqControlDto) data.getData();
                        byte[] command = control.getCommand();
                        // TODO: 전송성공하면

                        if (isRequested) {
                            this.vmsCtlr.getModule().setOnOff(true);
                            //this.vmsCtlr.getModule().setOnOff(command[0]);
                        } else {
                            int retry = this.vmsCtlr.getModule().getRetry();
                            retry++;
                            this.vmsCtlr.getModule().setRetry(retry);
                            this.vmsCtlr.getModule().setOnOff(false);
                        }
                        break;
                    default:
                        break;
                }
            } catch (Exception e) {
                log.error("TcpServerReqDataProcess[{}].process: Exception: {}", this.vmsCtlr.getCtlrNmbr(), e.toString());
            }
        }

        log.info("TcpServerReqDataProcess[{}].process: command({}), connected({}), Requested({}).", this.vmsCtlr.getCtlrNmbr(), data.getCommand(), isConnected, isRequested);

        MDC.remove(this.vmsCtlr.getLogKey());
        MDC.clear();
    }

    public void add(TcpServerSendData data) {
        try {
            //offer => full -> return
            //add   => full -> wait
            //큐가 차더라도 바로 리턴함.
            if (!this.reqCommandBlockingQueue.offer(data)) {
                log.error("TcpServerReqDataProcess[{}].add: QueueFull: {}", this.vmsCtlr.getCtlrNmbr(), this.reqCommandBlockingQueue.size());
            }
        } catch (Exception e) {
            log.error("TcpServerReqDataProcess[{}].add: QueueError: {}", this.vmsCtlr.getCtlrNmbr(), e.getMessage());
        }
    }

}
